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.
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::AlignToNearestPad( const VECTOR2I& aMousePos, std::deque<PAD*>& aPads )
395{
396 clearAnchors();
397
398 for( BOARD_ITEM* item : aPads )
399 computeAnchors( item, aMousePos, true, nullptr );
400
401 double minDist = std::numeric_limits<double>::max();
402 ANCHOR* nearestOrigin = nullptr;
403
404 for( ANCHOR& a : m_anchors )
405 {
406 if( ( ORIGIN & a.flags ) != ORIGIN )
407 continue;
408
409 bool hitAny = true;
410 for( EDA_ITEM* item : m_snapItem->items )
411 {
412 hitAny = hitAny && item->HitTest( aMousePos );
413 }
414
415 if( !hitAny )
416 continue;
417
418 double dist = a.Distance( aMousePos );
419
420 if( dist < minDist )
421 {
422 minDist = dist;
423 nearestOrigin = &a;
424 }
425 }
426
427 return nearestOrigin ? nearestOrigin->pos : aMousePos;
428}
429
430
432 std::vector<BOARD_ITEM*>& aItems,
433 GRID_HELPER_GRIDS aGrid,
434 const PCB_SELECTION_FILTER_OPTIONS* aSelectionFilter )
435{
436 clearAnchors();
437
438 computeAnchors( aItems, aMousePos, true, aSelectionFilter, nullptr, true );
439
440 double lineSnapMinCornerDistance = m_toolMgr->GetView()->ToWorld( 50 );
441
442 ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE );
443 ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER );
444 ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN );
445 ANCHOR* best = nullptr;
446 double minDist = std::numeric_limits<double>::max();
447
448 if( nearestOrigin )
449 {
450 minDist = nearestOrigin->Distance( aMousePos );
451 best = nearestOrigin;
452 }
453
454 if( nearestCorner )
455 {
456 double dist = nearestCorner->Distance( aMousePos );
457
458 if( dist < minDist )
459 {
460 minDist = dist;
461 best = nearestCorner;
462 }
463 }
464
465 if( nearestOutline )
466 {
467 double dist = nearestOutline->Distance( aMousePos );
468
469 if( minDist > lineSnapMinCornerDistance && dist < minDist )
470 best = nearestOutline;
471 }
472
473 return best ? best->pos : aMousePos;
474}
475
476
478 GRID_HELPER_GRIDS aGrid )
479{
480 LSET layers;
481 std::vector<BOARD_ITEM*> item;
482
483 if( aReferenceItem )
484 {
485 layers = aReferenceItem->GetLayerSet();
486 item.push_back( aReferenceItem );
487 }
488 else
489 {
490 layers = LSET::AllLayersMask();
491 }
492
493 return BestSnapAnchor( aOrigin, layers, aGrid, item );
494}
495
496
498 GRID_HELPER_GRIDS aGrid,
499 const std::vector<BOARD_ITEM*>& aSkip )
500{
501 // Tuning constant: snap radius in screen space
502 const int snapSize = 25;
503
504 // Snapping distance is in screen space, clamped to the current grid to ensure that the grid
505 // points that are visible can always be snapped to.
506 // see https://gitlab.com/kicad/code/kicad/-/issues/5638
507 // see https://gitlab.com/kicad/code/kicad/-/issues/7125
508 // see https://gitlab.com/kicad/code/kicad/-/issues/12303
509 double snapScale = m_toolMgr->GetView()->ToWorld( snapSize );
510 // warning: GetVisibleGrid().x sometimes returns a value > INT_MAX. Intermediate calculation
511 // needs double.
512 int snapRange = KiROUND( m_enableGrid ? std::min( snapScale, GetVisibleGrid().x ) : snapScale );
513
514 //Respect limits of coordinates representation
515 const BOX2I visibilityHorizon =
516 BOX2ISafe( VECTOR2D( aOrigin ) - snapRange / 2.0, VECTOR2D( snapRange, snapRange ) );
517
518 clearAnchors();
519
520 const std::vector<BOARD_ITEM*> visibleItems = queryVisible( visibilityHorizon, aSkip );
521 computeAnchors( visibleItems, aOrigin, false, nullptr, &aLayers, false );
522
523 ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE );
524 VECTOR2I nearestGrid = Align( aOrigin, aGrid );
525
527 {
528 ad->ClearAnchors();
529 for( const ANCHOR& anchor : m_anchors )
530 ad->AddAnchor( anchor.pos );
531
532 ad->SetNearest( nearest ? OPT_VECTOR2I{ nearest->pos } : std::nullopt );
534 }
535
536 // The distance to the nearest snap point, if any
537 std::optional<int> snapDist;
538 if( nearest )
539 snapDist = nearest->Distance( aOrigin );
540
542
543 SNAP_MANAGER& snapManager = getSnapManager();
544 SNAP_LINE_MANAGER& snapLineManager = snapManager.GetSnapLineManager();
545
546 const auto ptIsReferenceOnly = [&]( const VECTOR2I& aPt )
547 {
548 const std::vector<VECTOR2I>& referenceOnlyPoints = snapManager.GetReferenceOnlyPoints();
549 return std::find( referenceOnlyPoints.begin(), referenceOnlyPoints.end(), aPt )
550 != referenceOnlyPoints.end();
551 };
552
553 const auto proposeConstructionForItems = [&]( const std::vector<EDA_ITEM*>& aItems )
554 {
555 // Add any involved item as a temporary construction item
556 // (de-duplication with existing construction items is handled later)
557 std::vector<BOARD_ITEM*> items;
558
559 for( EDA_ITEM* item : aItems )
560 {
561 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( item );
562
563 // Null items are allowed to arrive here as they represent geometry that isn't
564 // specifically tied to a board item. For example snap lines from some
565 // other anchor.
566 // But they don't produce new construction items.
567 if( boardItem )
568 {
570 || ( ( aLayers & boardItem->GetLayerSet() ).any() ) )
571 {
572 items.push_back( boardItem );
573 }
574 }
575 }
576
577 // Temporary construction items are not persistent and don't
578 // overlay the items themselves (as the items will not be moved)
579 AddConstructionItems( items, true, false );
580 };
581
582 bool snapValid = false;
583
584 if( m_enableSnap )
585 {
586 // Existing snap lines need priority over new snaps
587 if( m_enableSnapLine )
588 {
589 OPT_VECTOR2I snapLineSnap = snapLineManager.GetNearestSnapLinePoint(
590 aOrigin, nearestGrid, snapDist, snapRange );
591
592 // We found a better snap point that the nearest one
593 if( snapLineSnap && m_skipPoint != *snapLineSnap )
594 {
595 snapLineManager.SetSnapLineEnd( *snapLineSnap );
596 snapValid = true;
597
598 // Don't show a snap point if we're snapping to a grid rather than an anchor
600 m_viewSnapPoint.SetSnapTypes( POINT_TYPE::PT_NONE );
601
602 // Only return the snap line end as a snap if it's not a reference point
603 // (we don't snap to reference points, but we can use them to update the snap line,
604 // without actually snapping)
605 if( !ptIsReferenceOnly( *snapLineSnap ) )
606 {
607 return *snapLineSnap;
608 }
609 }
610 }
611
612 // If there's a snap anchor within range, use it if we can
613 if( nearest && nearest->Distance( aOrigin ) <= snapRange )
614 {
615 const bool anchorIsConstructed = nearest->flags & ANCHOR_FLAGS::CONSTRUCTED;
616
617 // If the nearest anchor is a reference point, we don't snap to it,
618 // but we can update the snap line origin
619 if( ptIsReferenceOnly( nearest->pos ) )
620 {
621 // We can set the snap line origin, but don't mess with the
622 // accepted snap point
623 snapLineManager.SetSnapLineOrigin( nearest->pos );
624 }
625 else
626 {
627 // 'Intrinsic' points of items can trigger adding construction geometry
628 // for _that_ item by proximity. E.g. just mousing over the intersection
629 // of an item doesn't add a construction item for the second item).
630 // This is to make construction items less intrusive and more
631 // a result of user intent.
632 if( !anchorIsConstructed )
633 {
634 proposeConstructionForItems( nearest->items );
635 }
636
637 const auto shouldAcceptAnchor = [&]( const ANCHOR& aAnchor )
638 {
639 // If no extension snaps are enabled, don't inhibit
640 static const bool haveExtensions =
642 if( !haveExtensions )
643 return true;
644
645 // Check that any involved real items are 'active'
646 // (i.e. the user has moused over a key point previously)
647 // If any are not real (e.g. snap lines), they are allowed to be involved
648 //
649 // This is an area most likely to be controversial/need tuning,
650 // as some users will think it's fiddly; without 'activation', others will
651 // think the snaps are intrusive.
652 bool allRealAreInvolved =
654 aAnchor.items );
655 return allRealAreInvolved;
656 };
657
658 if( shouldAcceptAnchor( *nearest ) )
659 {
660 m_snapItem = *nearest;
661
662 // Set the snap line origin or end as needed
663 snapLineManager.SetSnappedAnchor( m_snapItem->pos );
664 // Show the correct snap point marker
665 updateSnapPoint( { m_snapItem->pos, m_snapItem->pointTypes } );
666
667 return m_snapItem->pos;
668 }
669 }
670
671 snapValid = true;
672 }
673 else
674 {
675 static const bool canActivateByHitTest =
677 if( canActivateByHitTest )
678 {
679 // An exact hit on an item, even if not near a snap point
680 // If it's tool hard to hit by hover, this can be increased
681 // to make it non-exact.
682 const int hoverAccuracy = 0;
683 for( BOARD_ITEM* item : visibleItems )
684 {
685 if( item->HitTest( aOrigin, hoverAccuracy ) )
686 {
687 proposeConstructionForItems( { item } );
688 snapValid = true;
689 break;
690 }
691 }
692 }
693 }
694
695 // If we got here, we didn't snap to an anchor or snap line
696
697 // If we're snapping to a grid, on-element snaps would be too intrusive
698 // but they're useful when there isn't a grid to snap to
699 if( !m_enableGrid )
700 {
701 OPT_VECTOR2I nearestPointOnAnElement =
703
704 // Got any nearest point - snap if in range
705 if( nearestPointOnAnElement
706 && nearestPointOnAnElement->Distance( aOrigin ) <= snapRange )
707 {
708 updateSnapPoint( { *nearestPointOnAnElement, POINT_TYPE::PT_ON_ELEMENT } );
709
710 // Clear the snap end, but keep the origin so touching another line
711 // doesn't kill a snap line
712 snapLineManager.SetSnapLineEnd( std::nullopt );
713 return *nearestPointOnAnElement;
714 }
715 }
716 }
717
718 // Completely failed to find any snap point, so snap to the grid
719
720 m_snapItem = std::nullopt;
721
722 if( !snapValid )
723 {
724 snapLineManager.ClearSnapLine();
726 }
727 else
728 {
729 snapLineManager.SetSnapLineEnd( std::nullopt );
730 }
731
733
734 return nearestGrid;
735}
736
737
739{
740 if( !m_snapItem )
741 return nullptr;
742
743 // The snap anchor doesn't have an item associated with it
744 // (odd, could it be entirely made of construction geometry?)
745 if( m_snapItem->items.empty() )
746 return nullptr;
747
748 return static_cast<BOARD_ITEM*>( m_snapItem->items[0] );
749}
750
751
753{
754 if( !aItem )
755 return GRID_CURRENT;
756
757 switch( aItem->Type() )
758 {
759 case PCB_FOOTPRINT_T:
760 case PCB_PAD_T:
761 return GRID_CONNECTABLE;
762
763 case PCB_TEXT_T:
764 case PCB_FIELD_T:
765 return GRID_TEXT;
766
767 case PCB_SHAPE_T:
768 case PCB_DIMENSION_T:
770 case PCB_TEXTBOX_T:
771 return GRID_GRAPHICS;
772
773 case PCB_TRACE_T:
774 case PCB_ARC_T:
775 return GRID_WIRES;
776
777 case PCB_VIA_T:
778 return GRID_VIAS;
779
780 default:
781 return GRID_CURRENT;
782 }
783}
784
785
787{
789 int idx = -1;
790
792
793 if( !grid.overrides_enabled )
794 return g;
795
796 switch( aGrid )
797 {
798 case GRID_CONNECTABLE:
799 if( grid.override_connected )
800 idx = grid.override_connected_idx;
801
802 break;
803
804 case GRID_WIRES:
805 if( grid.override_wires )
806 idx = grid.override_wires_idx;
807
808 break;
809
810 case GRID_VIAS:
811 if( grid.override_vias )
812 idx = grid.override_vias_idx;
813
814 break;
815
816 case GRID_TEXT:
817 if( grid.override_text )
818 idx = grid.override_text_idx;
819
820 break;
821
822 case GRID_GRAPHICS:
823 if( grid.override_graphics )
824 idx = grid.override_graphics_idx;
825
826 break;
827
828 default:
829 break;
830 }
831
832 if( idx >= 0 && idx < (int) grid.grids.size() )
833 g = grid.grids[idx].ToDouble( pcbIUScale );
834
835 return g;
836}
837
838
839std::vector<BOARD_ITEM*>
840PCB_GRID_HELPER::queryVisible( const BOX2I& aArea, const std::vector<BOARD_ITEM*>& aSkip ) const
841{
842 std::set<BOARD_ITEM*> items;
843 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
844
845 PCB_TOOL_BASE* currentTool = static_cast<PCB_TOOL_BASE*>( m_toolMgr->GetCurrentTool() );
846 KIGFX::VIEW* view = m_toolMgr->GetView();
847 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
848 const std::set<int>& activeLayers = settings->GetHighContrastLayers();
849 bool isHighContrast = settings->GetHighContrast();
850
851 view->Query( aArea, selectedItems );
852
853 for( const auto& [ viewItem, layer ] : selectedItems )
854 {
855 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( viewItem );
856
857 if( currentTool->IsFootprintEditor() )
858 {
859 // If we are in the footprint editor, don't use the footprint itself
860 if( boardItem->Type() == PCB_FOOTPRINT_T )
861 continue;
862 }
863 else
864 {
865 // If we are not in the footprint editor, don't use footprint-editor-private items
866 if( FOOTPRINT* parentFP = boardItem->GetParentFootprint() )
867 {
868 if( IsPcbLayer( layer ) && parentFP->GetPrivateLayers().test( layer ) )
869 continue;
870 }
871 }
872
873 // The boardItem must be visible and on an active layer
874 if( view->IsVisible( boardItem )
875 && ( !isHighContrast || activeLayers.count( layer ) )
876 && boardItem->ViewGetLOD( layer, view ) < view->GetScale() )
877 {
878 items.insert ( boardItem );
879 }
880 }
881
882 std::function<void( BOARD_ITEM* )> skipItem =
883 [&]( BOARD_ITEM* aItem )
884 {
885 items.erase( aItem );
886
887 aItem->RunOnDescendants(
888 [&]( BOARD_ITEM* aChild )
889 {
890 skipItem( aChild );
891 } );
892 };
893
894 for( BOARD_ITEM* item : aSkip )
895 skipItem( item );
896
897 return {items.begin(), items.end()};
898}
899
900
902{
905
906 // Clang wants this constructor
908 Item( aItem ), Geometry( std::move( aSeg ) )
909 {
910 }
911};
912
913
914void PCB_GRID_HELPER::computeAnchors( const std::vector<BOARD_ITEM*>& aItems,
915 const VECTOR2I& aRefPos, bool aFrom,
916 const PCB_SELECTION_FILTER_OPTIONS* aSelectionFilter,
917 const LSET* aMatchLayers, bool aForDrag )
918{
919 std::vector<PCB_INTERSECTABLE> intersectables;
920
921 // These could come from a more granular snap mode filter
922 // But when looking for drag points, we don't want construction geometry
923 const bool computeIntersections = !aForDrag;
924 const bool computePointsOnElements = !aForDrag;
925 const bool excludeGraphics = aSelectionFilter && !aSelectionFilter->graphics;
926 const bool excludeTracks = aSelectionFilter && !aSelectionFilter->tracks;
927
928 const auto itemIsSnappable = [&]( const BOARD_ITEM& aItem )
929 {
930 // If we are filtering by layers, check if the item matches
931 if( aMatchLayers )
932 {
934 || ( ( *aMatchLayers & aItem.GetLayerSet() ).any() );
935 }
936 return true;
937 };
938
939 const auto processItem = [&]( BOARD_ITEM& item )
940 {
941 // Don't even process the item if it doesn't match the layers
942 if( !itemIsSnappable( item ) )
943 {
944 return;
945 }
946
947 // First, add all the key points of the item itself
948 computeAnchors( &item, aRefPos, aFrom, aSelectionFilter );
949
950 // If we are computing intersections, construct the relevant intersectables
951 // Points on elements also use the intersectables.
952 if( computeIntersections || computePointsOnElements )
953 {
954 std::optional<INTERSECTABLE_GEOM> intersectableGeom;
955 if( !excludeGraphics && item.Type() == PCB_SHAPE_T )
956 {
957 intersectableGeom = GetBoardIntersectable( item );
958 }
959 else if( !excludeTracks && ( item.Type() == PCB_TRACE_T || item.Type() == PCB_ARC_T ) )
960 {
961 intersectableGeom = GetBoardIntersectable( item );
962 }
963
964 if( intersectableGeom )
965 {
966 intersectables.emplace_back( &item, *intersectableGeom );
967 }
968 }
969 };
970
971 for( BOARD_ITEM* item : aItems )
972 {
973 processItem( *item );
974 }
975
977 getSnapManager().GetConstructionItems() )
978 {
979 for( const CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM& constructionItem : batch )
980 {
981 BOARD_ITEM* involvedItem = static_cast<BOARD_ITEM*>( constructionItem.Item );
982
983
984 for( const KIGFX::CONSTRUCTION_GEOM::DRAWABLE& drawable :
985 constructionItem.Constructions )
986 {
987 std::visit(
988 [&]( const auto& visited )
989 {
990 using ItemType = std::decay_t<decltype( visited )>;
991
992 if constexpr( std::is_same_v<ItemType, LINE>
993 || std::is_same_v<ItemType, CIRCLE>
994 || std::is_same_v<ItemType, HALF_LINE>
995 || std::is_same_v<ItemType, SHAPE_ARC> )
996 {
997 intersectables.emplace_back( involvedItem, visited );
998 }
999 else if constexpr( std::is_same_v<ItemType, VECTOR2I> )
1000 {
1001 // Add any free-floating points as snap points.
1002 addAnchor( visited, SNAPPABLE | CONSTRUCTED, involvedItem,
1003 POINT_TYPE::PT_NONE );
1004 }
1005 },
1006 drawable );
1007 }
1008 }
1009 }
1010
1011 // Now, add all the intersections between the items
1012 // This is obviously quadratic, so performance may be a concern for large selections
1013 // But, so far up to ~20k comparisons seems not to be an issue with run times in the ms range
1014 // and it's usually only a handful of items.
1015
1016 if( computeIntersections )
1017 {
1018 for( std::size_t ii = 0; ii < intersectables.size(); ++ii )
1019 {
1020 const PCB_INTERSECTABLE& intersectableA = intersectables[ii];
1021
1022 for( std::size_t jj = ii + 1; jj < intersectables.size(); ++jj )
1023 {
1024 const PCB_INTERSECTABLE& intersectableB = intersectables[jj];
1025
1026 // An item and its own extension will often have intersections (as they are on top of each other),
1027 // but they not useful points to snap to
1028 if( intersectableA.Item == intersectableB.Item )
1029 continue;
1030
1031 std::vector<VECTOR2I> intersections;
1032 const INTERSECTION_VISITOR visitor{ intersectableA.Geometry, intersections };
1033
1034 std::visit( visitor, intersectableB.Geometry );
1035
1036 // For each intersection, add an intersection snap anchor
1037 for( const VECTOR2I& intersection : intersections )
1038 {
1039 std::vector<EDA_ITEM*> items = {
1040 intersectableA.Item,
1041 intersectableB.Item,
1042 };
1043 addAnchor( intersection, SNAPPABLE | CONSTRUCTED, std::move( items ),
1044 POINT_TYPE::PT_INTERSECTION );
1045 }
1046 }
1047 }
1048 }
1049
1050 // The intersectables can also be used for fall-back snapping to "point on line"
1051 // snaps if no other snap is found
1053 if( computePointsOnElements )
1054 {
1055 // For the moment, it's trivial to make a NEARABLE from an INTERSECTABLE,
1056 // because all INTERSECTABLEs are also NEARABLEs.
1057 for( const PCB_INTERSECTABLE& intersectable : intersectables )
1058 {
1059 std::visit(
1060 [&]( const auto& geom )
1061 {
1062 NEARABLE_GEOM nearable( geom );
1063 m_pointOnLineCandidates.emplace_back( nearable );
1064 },
1065 intersectable.Geometry );
1066 }
1067 }
1068}
1069
1070
1071void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos, bool aFrom,
1072 const PCB_SELECTION_FILTER_OPTIONS* aSelectionFilter )
1073{
1074 KIGFX::VIEW* view = m_toolMgr->GetView();
1075 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
1076 const std::set<int>& activeLayers = settings->GetHighContrastLayers();
1077 bool isHighContrast = settings->GetHighContrast();
1078
1079 auto checkVisibility =
1080 [&]( BOARD_ITEM* item )
1081 {
1082 if( !view->IsVisible( item ) )
1083 return false;
1084
1085 bool onActiveLayer = !isHighContrast;
1086 bool isLODVisible = false;
1087
1088 for( PCB_LAYER_ID layer : item->GetLayerSet().Seq() )
1089 {
1090 if( !onActiveLayer && activeLayers.count( layer ) )
1091 onActiveLayer = true;
1092
1093 if( !isLODVisible && item->ViewGetLOD( layer, view ) < view->GetScale() )
1094 isLODVisible = true;
1095
1096 if( onActiveLayer && isLODVisible )
1097 return true;
1098 }
1099
1100 return false;
1101 };
1102
1103 // As defaults, these are probably reasonable to avoid spamming key points
1104 const KIGEOM::OVAL_KEY_POINT_FLAGS ovalKeyPointFlags =
1107
1108 auto handlePadShape = [&]( PAD* aPad, PCB_LAYER_ID aLayer )
1109 {
1110 addAnchor( aPad->GetPosition(), ORIGIN | SNAPPABLE, aPad, POINT_TYPE::PT_CENTER );
1111
1113 if( aFrom )
1114 return;
1115
1116 switch( aPad->GetShape( aLayer ) )
1117 {
1118 case PAD_SHAPE::CIRCLE:
1119 {
1120 const CIRCLE circle( aPad->ShapePos( aLayer ), aPad->GetSizeX() / 2 );
1121
1122 for( const TYPED_POINT2I& pt : KIGEOM::GetCircleKeyPoints( circle, false ) )
1123 {
1124 addAnchor( pt.m_point, OUTLINE | SNAPPABLE, aPad, pt.m_types );
1125 }
1126
1127 break;
1128 }
1129 case PAD_SHAPE::OVAL:
1130 {
1131 const OVAL oval( aPad->GetSize( aLayer ), aPad->GetPosition(), aPad->GetOrientation() );
1132
1133 for( const TYPED_POINT2I& pt : KIGEOM::GetOvalKeyPoints( oval, ovalKeyPointFlags ) )
1134 {
1135 addAnchor( pt.m_point, OUTLINE | SNAPPABLE, aPad, pt.m_types );
1136 }
1137
1138 break;
1139 }
1140 case PAD_SHAPE::RECTANGLE:
1141 case PAD_SHAPE::TRAPEZOID:
1142 case PAD_SHAPE::ROUNDRECT:
1143 case PAD_SHAPE::CHAMFERED_RECT:
1144 {
1145 VECTOR2I half_size( aPad->GetSize( aLayer ) / 2 );
1146 VECTOR2I trap_delta( 0, 0 );
1147
1148 if( aPad->GetShape( aLayer ) == PAD_SHAPE::TRAPEZOID )
1149 trap_delta = aPad->GetDelta( aLayer ) / 2;
1150
1151 SHAPE_LINE_CHAIN corners;
1152
1153 corners.Append( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
1154 corners.Append( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
1155 corners.Append( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
1156 corners.Append( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
1157 corners.SetClosed( true );
1158
1159 corners.Rotate( aPad->GetOrientation() );
1160 corners.Move( aPad->ShapePos( aLayer ) );
1161
1162 for( std::size_t ii = 0; ii < corners.GetSegmentCount(); ++ii )
1163 {
1164 const SEG& seg = corners.GetSegment( ii );
1165 addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad, POINT_TYPE::PT_CORNER );
1166 addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad, POINT_TYPE::PT_MID );
1167
1168 if( ii == corners.GetSegmentCount() - 1 )
1169 addAnchor( seg.B, OUTLINE | SNAPPABLE, aPad, POINT_TYPE::PT_CORNER );
1170 }
1171
1172 break;
1173 }
1174
1175 default:
1176 {
1177 const auto& outline = aPad->GetEffectivePolygon( aLayer, ERROR_INSIDE );
1178
1179 if( !outline->IsEmpty() )
1180 {
1181 for( const VECTOR2I& pt : outline->Outline( 0 ).CPoints() )
1182 addAnchor( pt, OUTLINE | SNAPPABLE, aPad );
1183 }
1184
1185 break;
1186 }
1187 }
1188
1189 if( aPad->HasHole() )
1190 {
1191 // Holes are at the pad centre (it's the shape that may be offset)
1192 const VECTOR2I hole_pos = aPad->GetPosition();
1193 const VECTOR2I hole_size = aPad->GetDrillSize();
1194
1195 std::vector<TYPED_POINT2I> snap_pts;
1196
1197 if( hole_size.x == hole_size.y )
1198 {
1199 // Circle
1200 const CIRCLE circle( hole_pos, hole_size.x / 2 );
1201 snap_pts = KIGEOM::GetCircleKeyPoints( circle, true );
1202 }
1203 else
1204 {
1205 // Oval
1206
1207 // For now there's no way to have an off-angle hole, so this is the
1208 // same as the pad. In future, this may not be true:
1209 // https://gitlab.com/kicad/code/kicad/-/issues/4124
1210 const OVAL oval( hole_size, hole_pos, aPad->GetOrientation() );
1211 snap_pts = KIGEOM::GetOvalKeyPoints( oval, ovalKeyPointFlags );
1212 }
1213
1214 for( const TYPED_POINT2I& snap_pt : snap_pts )
1215 addAnchor( snap_pt.m_point, OUTLINE | SNAPPABLE, aPad, snap_pt.m_types );
1216 }
1217 };
1218
1219 auto handleShape =
1220 [&]( PCB_SHAPE* shape )
1221 {
1222 VECTOR2I start = shape->GetStart();
1223 VECTOR2I end = shape->GetEnd();
1224
1225 switch( shape->GetShape() )
1226 {
1227 case SHAPE_T::CIRCLE:
1228 {
1229 const int r = ( start - end ).EuclideanNorm();
1230
1231 addAnchor( start, ORIGIN | SNAPPABLE, shape, POINT_TYPE::PT_CENTER );
1232
1233 addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, shape,
1234 POINT_TYPE::PT_QUADRANT );
1235 addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, shape,
1236 POINT_TYPE::PT_QUADRANT );
1237 addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, shape,
1238 POINT_TYPE::PT_QUADRANT );
1239 addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, shape,
1240 POINT_TYPE::PT_QUADRANT );
1241 break;
1242 }
1243
1244 case SHAPE_T::ARC:
1245 addAnchor( shape->GetStart(), CORNER | SNAPPABLE, shape,
1246 POINT_TYPE::PT_END );
1247 addAnchor( shape->GetEnd(), CORNER | SNAPPABLE, shape,
1248 POINT_TYPE::PT_END );
1249 addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape,
1250 POINT_TYPE::PT_MID );
1251 addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape,
1252 POINT_TYPE::PT_CENTER );
1253 break;
1254
1255 case SHAPE_T::RECTANGLE:
1256 {
1257 VECTOR2I point2( end.x, start.y );
1258 VECTOR2I point3( start.x, end.y );
1259 SEG first( start, point2 );
1260 SEG second( point2, end );
1261 SEG third( end, point3 );
1262 SEG fourth( point3, start );
1263
1264 const int snapFlags = CORNER | SNAPPABLE;
1265
1266 addAnchor( shape->GetCenter(), snapFlags, shape, POINT_TYPE::PT_CENTER );
1267
1268 addAnchor( first.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
1269 addAnchor( first.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
1270 addAnchor( second.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
1271 addAnchor( second.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
1272 addAnchor( third.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
1273 addAnchor( third.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
1274 addAnchor( fourth.A, snapFlags, shape, POINT_TYPE::PT_CORNER );
1275 addAnchor( fourth.Center(), snapFlags, shape, POINT_TYPE::PT_MID );
1276 break;
1277 }
1278
1279 case SHAPE_T::SEGMENT:
1280 addAnchor( start, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
1281 addAnchor( end, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
1282 addAnchor( shape->GetCenter(), CORNER | SNAPPABLE, shape,
1283 POINT_TYPE::PT_MID );
1284 break;
1285
1286 case SHAPE_T::POLY:
1287 {
1289 lc.SetClosed( true );
1290 std::vector<VECTOR2I> poly;
1291 shape->DupPolyPointsList( poly );
1292
1293 for( const VECTOR2I& p : poly )
1294 {
1295 addAnchor( p, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_CORNER );
1296 lc.Append( p );
1297 }
1298
1299 addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
1300 break;
1301 }
1302
1303 case SHAPE_T::BEZIER:
1304 addAnchor( start, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
1305 addAnchor( end, CORNER | SNAPPABLE, shape, POINT_TYPE::PT_END );
1307
1308 default:
1309 addAnchor( shape->GetPosition(), ORIGIN | SNAPPABLE, shape );
1310 break;
1311 }
1312 };
1313
1314 switch( aItem->Type() )
1315 {
1316 case PCB_FOOTPRINT_T:
1317 {
1318 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
1319
1320 for( PAD* pad : footprint->Pads() )
1321 {
1322 if( aFrom )
1323 {
1324 if( aSelectionFilter && !aSelectionFilter->pads )
1325 continue;
1326 }
1327 else
1328 {
1329 if( m_magneticSettings->pads != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
1330 continue;
1331 }
1332
1333 if( !checkVisibility( pad ) )
1334 continue;
1335
1336 if( !pad->GetBoundingBox().Contains( aRefPos ) )
1337 continue;
1338
1339 pad->Padstack().ForEachUniqueLayer(
1340 [&]( PCB_LAYER_ID aLayer )
1341 {
1342 if( activeLayers.count( aLayer ) )
1343 handlePadShape( pad, aLayer );
1344 } );
1345 }
1346
1347 if( aFrom && aSelectionFilter && !aSelectionFilter->footprints )
1348 break;
1349
1350 // If the cursor is not over a pad, snap to the anchor (if visible) or the center
1351 // (if markedly different from the anchor).
1352 VECTOR2I position = footprint->GetPosition();
1353 VECTOR2I center = footprint->GetBoundingBox( false ).Centre();
1354 VECTOR2I grid( GetGrid() );
1355
1356 if( view->IsLayerVisible( LAYER_ANCHOR ) )
1357 addAnchor( position, ORIGIN | SNAPPABLE, footprint, POINT_TYPE::PT_CENTER );
1358
1359 if( ( center - position ).SquaredEuclideanNorm() > grid.SquaredEuclideanNorm() )
1360 addAnchor( center, ORIGIN | SNAPPABLE, footprint, POINT_TYPE::PT_CENTER );
1361
1362 break;
1363 }
1364
1365 case PCB_PAD_T:
1366 if( aFrom )
1367 {
1368 if( aSelectionFilter && !aSelectionFilter->pads )
1369 break;
1370 }
1371 else
1372 {
1373 if( m_magneticSettings->pads != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
1374 break;
1375 }
1376
1377 if( checkVisibility( aItem ) )
1378 {
1379 PAD* pad = static_cast<PAD*>( aItem );
1380
1381 pad->Padstack().ForEachUniqueLayer(
1382 [&]( PCB_LAYER_ID aLayer )
1383 {
1384 if( activeLayers.count( aLayer ) )
1385 handlePadShape( pad, aLayer );
1386 } );
1387 }
1388
1389 break;
1390
1391 case PCB_TEXTBOX_T:
1392 if( aFrom )
1393 {
1394 if( aSelectionFilter && !aSelectionFilter->text )
1395 break;
1396 }
1397 else
1398 {
1400 break;
1401 }
1402
1403 if( checkVisibility( aItem ) )
1404 handleShape( static_cast<PCB_SHAPE*>( aItem ) );
1405
1406 break;
1407
1408 case PCB_SHAPE_T:
1409 if( aFrom )
1410 {
1411 if( aSelectionFilter && !aSelectionFilter->graphics )
1412 break;
1413 }
1414 else
1415 {
1417 break;
1418 }
1419
1420 if( checkVisibility( aItem ) )
1421 handleShape( static_cast<PCB_SHAPE*>( aItem ) );
1422
1423 break;
1424
1425 case PCB_TRACE_T:
1426 case PCB_ARC_T:
1427 if( aFrom )
1428 {
1429 if( aSelectionFilter && !aSelectionFilter->tracks )
1430 break;
1431 }
1432 else
1433 {
1434 if( m_magneticSettings->tracks != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
1435 break;
1436 }
1437
1438 if( checkVisibility( aItem ) )
1439 {
1440 PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem );
1441
1442 addAnchor( track->GetStart(), CORNER | SNAPPABLE, track, POINT_TYPE::PT_END );
1443 addAnchor( track->GetEnd(), CORNER | SNAPPABLE, track, POINT_TYPE::PT_END );
1444 addAnchor( track->GetCenter(), ORIGIN, track, POINT_TYPE::PT_MID );
1445 }
1446
1447 break;
1448
1449 case PCB_MARKER_T:
1450 case PCB_TARGET_T:
1451 addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem,
1452 POINT_TYPE::PT_CENTER );
1453 break;
1454
1455 case PCB_VIA_T:
1456 if( aFrom )
1457 {
1458 if( aSelectionFilter && !aSelectionFilter->vias )
1459 break;
1460 }
1461 else
1462 {
1463 if( m_magneticSettings->tracks != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
1464 break;
1465 }
1466
1467 if( checkVisibility( aItem ) )
1468 addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem,
1469 POINT_TYPE::PT_CENTER );
1470
1471 break;
1472
1473 case PCB_ZONE_T:
1474 if( aFrom && aSelectionFilter && !aSelectionFilter->zones )
1475 break;
1476
1477 if( checkVisibility( aItem ) )
1478 {
1479 const SHAPE_POLY_SET* outline = static_cast<const ZONE*>( aItem )->Outline();
1480
1482 lc.SetClosed( true );
1483
1484 for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
1485 {
1486 addAnchor( *iter, CORNER | SNAPPABLE, aItem, POINT_TYPE::PT_CORNER );
1487 lc.Append( *iter );
1488 }
1489
1490 addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
1491 }
1492
1493 break;
1494
1495 case PCB_DIM_ALIGNED_T:
1497 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
1498 break;
1499
1500 if( checkVisibility( aItem ) )
1501 {
1502 const PCB_DIM_ALIGNED* dim = static_cast<const PCB_DIM_ALIGNED*>( aItem );
1503 addAnchor( dim->GetCrossbarStart(), CORNER | SNAPPABLE, aItem );
1504 addAnchor( dim->GetCrossbarEnd(), CORNER | SNAPPABLE, aItem );
1505 addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
1506 addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
1507 }
1508
1509 break;
1510
1511 case PCB_DIM_CENTER_T:
1512 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
1513 break;
1514
1515 if( checkVisibility( aItem ) )
1516 {
1517 const PCB_DIM_CENTER* dim = static_cast<const PCB_DIM_CENTER*>( aItem );
1518 addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
1519 addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
1520
1521 VECTOR2I start( dim->GetStart() );
1522 VECTOR2I radial( dim->GetEnd() - dim->GetStart() );
1523
1524 for( int i = 0; i < 2; i++ )
1525 {
1526 RotatePoint( radial, -ANGLE_90 );
1527 addAnchor( start + radial, CORNER | SNAPPABLE, aItem );
1528 }
1529 }
1530
1531 break;
1532
1533 case PCB_DIM_RADIAL_T:
1534 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
1535 break;
1536
1537 if( checkVisibility( aItem ) )
1538 {
1539 const PCB_DIM_RADIAL* radialDim = static_cast<const PCB_DIM_RADIAL*>( aItem );
1540 addAnchor( radialDim->GetStart(), CORNER | SNAPPABLE, aItem );
1541 addAnchor( radialDim->GetEnd(), CORNER | SNAPPABLE, aItem );
1542 addAnchor( radialDim->GetKnee(), CORNER | SNAPPABLE, aItem );
1543 addAnchor( radialDim->GetTextPos(), CORNER | SNAPPABLE, aItem );
1544 }
1545
1546 break;
1547
1548 case PCB_DIM_LEADER_T:
1549 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
1550 break;
1551
1552 if( checkVisibility( aItem ) )
1553 {
1554 const PCB_DIM_LEADER* leader = static_cast<const PCB_DIM_LEADER*>( aItem );
1555 addAnchor( leader->GetStart(), CORNER | SNAPPABLE, aItem );
1556 addAnchor( leader->GetEnd(), CORNER | SNAPPABLE, aItem );
1557 addAnchor( leader->GetTextPos(), CORNER | SNAPPABLE, aItem );
1558 }
1559
1560 break;
1561
1562 case PCB_FIELD_T:
1563 case PCB_TEXT_T:
1564 if( aFrom && aSelectionFilter && !aSelectionFilter->text )
1565 break;
1566
1567 if( checkVisibility( aItem ) )
1568 addAnchor( aItem->GetPosition(), ORIGIN, aItem );
1569
1570 break;
1571
1572 case PCB_GROUP_T:
1573 for( BOARD_ITEM* item : static_cast<const PCB_GROUP*>( aItem )->GetItems() )
1574 {
1575 if( checkVisibility( item ) )
1576 computeAnchors( item, aRefPos, aFrom, nullptr );
1577 }
1578
1579 break;
1580
1581 default:
1582 break;
1583 }
1584}
1585
1586
1588{
1589 // Do this all in squared distances as we only care about relative distances
1591
1592 ecoord minDist = std::numeric_limits<ecoord>::max();
1593 std::vector<ANCHOR*> anchorsAtMinDistance;
1594
1595 for( ANCHOR& anchor : m_anchors )
1596 {
1597 // There is no need to filter by layers here, as the items are already filtered
1598 // by layer (if needed) when the anchors are computed.
1599 if( ( aFlags & anchor.flags ) != aFlags )
1600 continue;
1601
1602 if( !anchorsAtMinDistance.empty() && anchor.pos == anchorsAtMinDistance.front()->pos )
1603 {
1604 // Same distance as the previous best anchor
1605 anchorsAtMinDistance.push_back( &anchor );
1606 }
1607 else
1608 {
1609 const double dist = anchor.pos.SquaredDistance( aPos );
1610 if( dist < minDist )
1611 {
1612 // New minimum distance
1613 minDist = dist;
1614 anchorsAtMinDistance.clear();
1615 anchorsAtMinDistance.push_back( &anchor );
1616 }
1617 }
1618 }
1619
1620 // More than one anchor can be at the same distance, for example
1621 // two lines end-to-end each have the same endpoint anchor.
1622 // So, check which one has an involved item that's closest to the origin,
1623 // and use that one (which allows the user to choose which items
1624 // gets extended - it's the one nearest the cursor)
1625 ecoord minDistToItem = std::numeric_limits<ecoord>::max();
1626 ANCHOR* best = nullptr;
1627
1628 // One of the anchors at the minimum distance
1629 for( ANCHOR* const anchor : anchorsAtMinDistance )
1630 {
1631 ecoord distToNearestItem = std::numeric_limits<ecoord>::max();
1632 for( EDA_ITEM* const item : anchor->items )
1633 {
1634 if( !item )
1635 continue;
1636
1637 std::optional<ecoord> distToThisItem =
1638 FindSquareDistanceToItem( static_cast<const BOARD_ITEM&>( *item ), aPos );
1639
1640 if( distToThisItem )
1641 distToNearestItem = std::min( distToNearestItem, *distToThisItem );
1642 }
1643
1644 // If the item doesn't have any special min-dist handler,
1645 // just use the distance to the anchor
1646 distToNearestItem = std::min( distToNearestItem, minDist );
1647
1648 if( distToNearestItem < minDistToItem )
1649 {
1650 minDistToItem = distToNearestItem;
1651 best = anchor;
1652 }
1653 }
1654
1655 return best;
1656}
@ 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:172
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:80
virtual VECTOR2I GetCenter() const
This defaults to the center of the bounding box if not overridden.
Definition: board_item.h:112
FOOTPRINT * GetParentFootprint() const
Definition: board_item.cpp:299
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:258
virtual void RunOnDescendants(const std::function< void(BOARD_ITEM *)> &aFunction, int aDepth=0) const
Invoke a function on all descendants.
Definition: board_item.h:213
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 CancelProposal()
Cancel outstanding proposals for new geometry.
std::vector< CONSTRUCTION_ITEM > CONSTRUCTION_ITEM_BATCH
void ProposeConstructionItems(CONSTRUCTION_ITEM_BATCH aBatch, bool aIsPersistent)
Add a batch of construction items to the helper.
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
int GetRadius() const
Definition: eda_shape.cpp:575
SHAPE_T GetShape() const
Definition: eda_shape.h:125
const VECTOR2I & GetEnd() const
Return the ending point of the graphic.
Definition: eda_shape.h:167
void DupPolyPointsList(std::vector< VECTOR2I > &aBuffer) const
Duplicate the list of corners in a std::vector<VECTOR2I>
Definition: eda_shape.cpp:1302
const VECTOR2I & GetStart() const
Return the starting point of the graphic.
Definition: eda_shape.h:130
VECTOR2I GetArcMid() const
Definition: eda_shape.cpp:545
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:253
std::deque< PAD * > & Pads()
Definition: footprint.h:205
VECTOR2I GetPosition() const override
Definition: footprint.h:223
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:1245
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:44
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:145
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:277
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:317
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:357
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:437
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:1687
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:203
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:484
bool IsLayerVisible(int aLayer) const
Return information about visibility of a particular layer.
Definition: view.h:418
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:221
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1657
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1614
Definition: line.h:36
LSET is a set of PCB_LAYER_IDs.
Definition: lset.h:36
static LSET AllLayersMask()
Definition: lset.cpp:701
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
Definition: lset.cpp:410
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:474
bool HasHole() const override
Definition: pad.h:104
VECTOR2I ShapePos(PCB_LAYER_ID aLayer) const
Definition: pad.cpp:966
const VECTOR2I & GetSize(PCB_LAYER_ID aLayer) const
Definition: pad.h:266
const VECTOR2I & GetMid() const
Definition: pcb_track.h:299
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)
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)
VECTOR2I AlignToNearestPad(const VECTOR2I &aMousePos, std::deque< PAD * > &aPads)
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:521
@ LAYER_AUX_ITEMS
Auxiliary items (guides, rule, etc)
Definition: layer_ids.h:224
@ LAYER_ANCHOR
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:203
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