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 <pcb_dimension.h>
31#include <pcb_shape.h>
32#include <footprint.h>
33#include <pad.h>
34#include <pcb_group.h>
35#include <pcb_track.h>
36#include <zone.h>
38#include <geometry/oval.h>
41#include <geometry/shape_rect.h>
44#include <macros.h>
45#include <math/util.h> // for KiROUND
46#include <gal/painter.h>
47#include <pcbnew_settings.h>
48#include <tool/tool_manager.h>
49#include <tools/pcb_tool_base.h>
50#include <view/view.h>
51
53 GRID_HELPER( aToolMgr ),
54 m_magneticSettings( aMagneticSettings )
55{
56 KIGFX::VIEW* view = m_toolMgr->GetView();
57 KIGFX::RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
58 KIGFX::COLOR4D auxItemsColor = settings->GetLayerColor( LAYER_AUX_ITEMS );
59 KIGFX::COLOR4D umbilicalColor = settings->GetLayerColor( LAYER_ANCHOR );
60
61 m_viewAxis.SetSize( 20000 );
63 m_viewAxis.SetColor( auxItemsColor.WithAlpha( 0.4 ) );
65 view->Add( &m_viewAxis );
66 view->SetVisible( &m_viewAxis, false );
67
69 m_viewSnapPoint.SetColor( auxItemsColor );
71 view->Add( &m_viewSnapPoint );
72 view->SetVisible( &m_viewSnapPoint, false );
73
75 m_viewSnapLine.SetColor( umbilicalColor );
77 view->Add( &m_viewSnapLine );
78 view->SetVisible( &m_viewSnapLine, false );
79}
80
81
83{
84 KIGFX::VIEW* view = m_toolMgr->GetView();
85
86 view->Remove( &m_viewAxis );
87 view->Remove( &m_viewSnapPoint );
88 view->Remove( &m_viewSnapLine );
89}
90
91
93{
94 const int c_gridSnapEpsilon_sq = 4;
95
96 VECTOR2I aligned = Align( aPoint );
97
98 if( !m_enableSnap )
99 return aligned;
100
101 std::vector<VECTOR2I> points;
102
103 const SEG testSegments[] = { SEG( aligned, aligned + VECTOR2( 1, 0 ) ),
104 SEG( aligned, aligned + VECTOR2( 0, 1 ) ),
105 SEG( aligned, aligned + VECTOR2( 1, 1 ) ),
106 SEG( aligned, aligned + VECTOR2( 1, -1 ) ) };
107
108 for( const SEG& seg : testSegments )
109 {
110 OPT_VECTOR2I vec = aSeg.IntersectLines( seg );
111
112 if( vec && aSeg.SquaredDistance( *vec ) <= c_gridSnapEpsilon_sq )
113 points.push_back( *vec );
114 }
115
116 VECTOR2I nearest = aligned;
118
119 // Snap by distance between pointer and endpoints
120 for( const VECTOR2I& pt : { aSeg.A, aSeg.B } )
121 {
122 SEG::ecoord d_sq = ( pt - aPoint ).SquaredEuclideanNorm();
123
124 if( d_sq < min_d_sq )
125 {
126 min_d_sq = d_sq;
127 nearest = pt;
128 }
129 }
130
131 // Snap by distance between aligned cursor and intersections
132 for( const VECTOR2I& pt : points )
133 {
134 SEG::ecoord d_sq = ( pt - aligned ).SquaredEuclideanNorm();
135
136 if( d_sq < min_d_sq )
137 {
138 min_d_sq = d_sq;
139 nearest = pt;
140 }
141 }
142
143 return nearest;
144}
145
146
148{
149 VECTOR2I aligned = Align( aPoint );
150
151 if( !m_enableSnap )
152 return aligned;
153
154 std::vector<VECTOR2I> points;
155
156 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 1, 0 ) ), &points );
157 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 0, 1 ) ), &points );
158 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 1, 1 ) ), &points );
159 aArc.IntersectLine( SEG( aligned, aligned + VECTOR2( 1, -1 ) ), &points );
160
161 VECTOR2I nearest = aligned;
163
164 // Snap by distance between pointer and endpoints
165 for( const VECTOR2I& pt : { aArc.GetP0(), aArc.GetP1() } )
166 {
167 SEG::ecoord d_sq = ( pt - aPoint ).SquaredEuclideanNorm();
168
169 if( d_sq < min_d_sq )
170 {
171 min_d_sq = d_sq;
172 nearest = pt;
173 }
174 }
175
176 // Snap by distance between aligned cursor and intersections
177 for( const VECTOR2I& pt : points )
178 {
179 SEG::ecoord d_sq = ( pt - aligned ).SquaredEuclideanNorm();
180
181 if( d_sq < min_d_sq )
182 {
183 min_d_sq = d_sq;
184 nearest = pt;
185 }
186 }
187
188 return nearest;
189}
190
191
193{
194 clearAnchors();
195
196 for( BOARD_ITEM* item : aPads )
197 computeAnchors( item, aMousePos, true );
198
199 double minDist = std::numeric_limits<double>::max();
200 ANCHOR* nearestOrigin = nullptr;
201
202 for( ANCHOR& a : m_anchors )
203 {
204 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( a.item );
205
206 if( ( ORIGIN & a.flags ) != ORIGIN )
207 continue;
208
209 if( !item->HitTest( aMousePos ) )
210 continue;
211
212 double dist = a.Distance( aMousePos );
213
214 if( dist < minDist )
215 {
216 minDist = dist;
217 nearestOrigin = &a;
218 }
219 }
220
221 return nearestOrigin ? nearestOrigin->pos : aMousePos;
222}
223
224
226 std::vector<BOARD_ITEM*>& aItems,
227 GRID_HELPER_GRIDS aGrid,
228 const PCB_SELECTION_FILTER_OPTIONS* aSelectionFilter )
229{
230 clearAnchors();
231
232 for( BOARD_ITEM* item : aItems )
233 computeAnchors( item, aMousePos, true, aSelectionFilter );
234
235 double worldScale = m_toolMgr->GetView()->GetGAL()->GetWorldScale();
236 double lineSnapMinCornerDistance = 50.0 / worldScale;
237
238 ANCHOR* nearestOutline = nearestAnchor( aMousePos, OUTLINE, LSET::AllLayersMask() );
239 ANCHOR* nearestCorner = nearestAnchor( aMousePos, CORNER, LSET::AllLayersMask() );
240 ANCHOR* nearestOrigin = nearestAnchor( aMousePos, ORIGIN, LSET::AllLayersMask() );
241 ANCHOR* best = nullptr;
242 double minDist = std::numeric_limits<double>::max();
243
244 if( nearestOrigin )
245 {
246 minDist = nearestOrigin->Distance( aMousePos );
247 best = nearestOrigin;
248 }
249
250 if( nearestCorner )
251 {
252 double dist = nearestCorner->Distance( aMousePos );
253
254 if( dist < minDist )
255 {
256 minDist = dist;
257 best = nearestCorner;
258 }
259 }
260
261 if( nearestOutline )
262 {
263 double dist = nearestOutline->Distance( aMousePos );
264
265 if( minDist > lineSnapMinCornerDistance && dist < minDist )
266 best = nearestOutline;
267 }
268
269 return best ? best->pos : aMousePos;
270}
271
272
274 GRID_HELPER_GRIDS aGrid )
275{
276 LSET layers;
277 std::vector<BOARD_ITEM*> item;
278
279 if( aReferenceItem )
280 {
281 layers = aReferenceItem->GetLayerSet();
282 item.push_back( aReferenceItem );
283 }
284 else
285 {
286 layers = LSET::AllLayersMask();
287 }
288
289 return BestSnapAnchor( aOrigin, layers, aGrid, item );
290}
291
292
294 GRID_HELPER_GRIDS aGrid,
295 const std::vector<BOARD_ITEM*>& aSkip )
296{
297 // Tuning constant: snap radius in screen space
298 const int snapSize = 25;
299
300 // Snapping distance is in screen space, clamped to the current grid to ensure that the grid
301 // points that are visible can always be snapped to.
302 // see https://gitlab.com/kicad/code/kicad/-/issues/5638
303 // see https://gitlab.com/kicad/code/kicad/-/issues/7125
304 // see https://gitlab.com/kicad/code/kicad/-/issues/12303
305 double snapScale = snapSize / m_toolMgr->GetView()->GetGAL()->GetWorldScale();
306 // warning: GetVisibleGrid().x sometimes returns a value > INT_MAX. Intermediate calculation
307 // needs double.
308 int snapRange = KiROUND( m_enableGrid ? std::min( snapScale, GetVisibleGrid().x ) : snapScale );
309 int snapDist = snapRange;
310
311 //Respect limits of coordinates representation
312 BOX2I bb;
313 bb.SetOrigin( GetClampedCoords<double, int>( VECTOR2D( aOrigin ) - snapRange / 2.0 ) );
314 bb.SetEnd( GetClampedCoords<double, int>( VECTOR2D( aOrigin ) + snapRange / 2.0 ) );
315
316 clearAnchors();
317
318 for( BOARD_ITEM* item : queryVisible( bb, aSkip ) )
319 computeAnchors( item, aOrigin );
320
321 ANCHOR* nearest = nearestAnchor( aOrigin, SNAPPABLE, aLayers );
322 VECTOR2I nearestGrid = Align( aOrigin, aGrid );
323
324 if( nearest )
325 snapDist = nearest->Distance( aOrigin );
326
327 // Existing snap lines need priority over new snaps
329 {
330 bool snapLine = false;
331 int x_dist = std::abs( m_viewSnapLine.GetPosition().x - aOrigin.x );
332 int y_dist = std::abs( m_viewSnapLine.GetPosition().y - aOrigin.y );
333
335 if( x_dist < snapRange && ( !nearest || snapDist > snapRange ) )
336 {
337 nearestGrid.x = m_viewSnapLine.GetPosition().x;
338 snapLine = true;
339 }
340
341 if( y_dist < snapRange && ( !nearest || snapDist > snapRange ) )
342 {
343 nearestGrid.y = m_viewSnapLine.GetPosition().y;
344 snapLine = true;
345 }
346
347 if( snapLine && m_skipPoint != VECTOR2I( m_viewSnapLine.GetPosition() ) )
348 {
349 m_viewSnapLine.SetEndPosition( nearestGrid );
350
353 else
355
356 return nearestGrid;
357 }
358 }
359
360 if( nearest && m_enableSnap )
361 {
362 if( nearest->Distance( aOrigin ) <= snapRange )
363 {
364 m_viewSnapPoint.SetPosition( nearest->pos );
365 m_viewSnapLine.SetPosition( nearest->pos );
367
370 else
372
373 m_snapItem = nearest;
374 return nearest->pos;
375 }
376 }
377
378 m_snapItem = nullptr;
381 return nearestGrid;
382}
383
384
386{
387 if( !m_snapItem )
388 return nullptr;
389
390 return static_cast<BOARD_ITEM*>( m_snapItem->item );
391}
392
393
395{
396 if( !aItem )
397 return GRID_CURRENT;
398
399 switch( aItem->Type() )
400 {
401 case PCB_FOOTPRINT_T:
402 case PCB_PAD_T:
403 return GRID_CONNECTABLE;
404
405 case PCB_TEXT_T:
406 case PCB_FIELD_T:
407 return GRID_TEXT;
408
409 case PCB_SHAPE_T:
410 case PCB_DIMENSION_T:
412 case PCB_TEXTBOX_T:
413 return GRID_GRAPHICS;
414
415 case PCB_TRACE_T:
416 case PCB_ARC_T:
417 return GRID_WIRES;
418
419 case PCB_VIA_T:
420 return GRID_VIAS;
421
422 default:
423 return GRID_CURRENT;
424 }
425}
426
427
429{
431 int idx = -1;
432
434
435 if( !grid.overrides_enabled )
436 return g;
437
438 switch( aGrid )
439 {
440 case GRID_CONNECTABLE:
441 if( grid.override_connected )
442 idx = grid.override_connected_idx;
443
444 break;
445
446 case GRID_WIRES:
447 if( grid.override_wires )
448 idx = grid.override_wires_idx;
449
450 break;
451
452 case GRID_VIAS:
453 if( grid.override_vias )
454 idx = grid.override_vias_idx;
455
456 break;
457
458 case GRID_TEXT:
459 if( grid.override_text )
460 idx = grid.override_text_idx;
461
462 break;
463
464 case GRID_GRAPHICS:
465 if( grid.override_graphics )
466 idx = grid.override_graphics_idx;
467
468 break;
469
470 default:
471 break;
472 }
473
474 if( idx >= 0 && idx < (int) grid.grids.size() )
475 g = grid.grids[idx].ToDouble( pcbIUScale );
476
477 return g;
478}
479
480
481std::set<BOARD_ITEM*> PCB_GRID_HELPER::queryVisible( const BOX2I& aArea,
482 const std::vector<BOARD_ITEM*>& aSkip ) const
483{
484 std::set<BOARD_ITEM*> items;
485 std::vector<KIGFX::VIEW::LAYER_ITEM_PAIR> selectedItems;
486
487 PCB_TOOL_BASE* currentTool = static_cast<PCB_TOOL_BASE*>( m_toolMgr->GetCurrentTool() );
488 KIGFX::VIEW* view = m_toolMgr->GetView();
489 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
490 const std::set<int>& activeLayers = settings->GetHighContrastLayers();
491 bool isHighContrast = settings->GetHighContrast();
492
493 view->Query( aArea, selectedItems );
494
495 for( const auto& [ viewItem, layer ] : selectedItems )
496 {
497 BOARD_ITEM* boardItem = static_cast<BOARD_ITEM*>( viewItem );
498
499 if( currentTool->IsFootprintEditor() )
500 {
501 // If we are in the footprint editor, don't use the footprint itself
502 if( boardItem->Type() == PCB_FOOTPRINT_T )
503 continue;
504 }
505 else
506 {
507 // If we are not in the footprint editor, don't use footprint-editor-private items
508 if( FOOTPRINT* parentFP = boardItem->GetParentFootprint() )
509 {
510 if( IsPcbLayer( layer ) && parentFP->GetPrivateLayers().test( layer ) )
511 continue;
512 }
513 }
514
515 // The boardItem must be visible and on an active layer
516 if( view->IsVisible( boardItem )
517 && ( !isHighContrast || activeLayers.count( layer ) )
518 && boardItem->ViewGetLOD( layer, view ) < view->GetScale() )
519 {
520 items.insert ( boardItem );
521 }
522 }
523
524 std::function<void( BOARD_ITEM* )> skipItem =
525 [&]( BOARD_ITEM* aItem )
526 {
527 items.erase( aItem );
528
529 aItem->RunOnDescendants(
530 [&]( BOARD_ITEM* aChild )
531 {
532 skipItem( aChild );
533 } );
534 };
535
536 for( BOARD_ITEM* item : aSkip )
537 skipItem( item );
538
539 return items;
540}
541
542
543void PCB_GRID_HELPER::computeAnchors( BOARD_ITEM* aItem, const VECTOR2I& aRefPos, bool aFrom,
544 const PCB_SELECTION_FILTER_OPTIONS* aSelectionFilter )
545{
546 KIGFX::VIEW* view = m_toolMgr->GetView();
547 RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
548 const std::set<int>& activeLayers = settings->GetHighContrastLayers();
549 bool isHighContrast = settings->GetHighContrast();
550
551 // As defaults, these are probably reasonable to avoid spamming key points
552 const OVAL_KEY_POINT_FLAGS ovalKeyPointFlags =
554
555 // The key points of a circle centred around (0, 0) with the given radius
556 const auto getCircleKeyPoints = [] ( int radius )
557 {
558 return std::vector<VECTOR2I>{
559 {0, 0},
560 { -radius, 0 },
561 { radius, 0 },
562 { 0, -radius },
563 { 0, radius }
564 };
565 };
566
567 auto handlePadShape =
568 [&]( PAD* aPad )
569 {
570 addAnchor( aPad->GetPosition(), ORIGIN | SNAPPABLE, aPad );
571
573 if( aFrom )
574 return;
575
576 switch( aPad->GetShape() )
577 {
578 case PAD_SHAPE::CIRCLE:
579 {
580 int r = aPad->GetSizeX() / 2;
581 VECTOR2I center = aPad->ShapePos();
582
583 const std::vector<VECTOR2I> circle_pts = getCircleKeyPoints( r );
584
585 for ( const VECTOR2I& pt: circle_pts ) {
586 // Transform to the pad positon
587 addAnchor( center + pt, OUTLINE | SNAPPABLE, aPad );
588 }
589 break;
590 }
591
592 case PAD_SHAPE::OVAL:
593 {
594 const VECTOR2I pos = aPad->ShapePos();
595
596 const std::vector<VECTOR2I> oval_pts = GetOvalKeyPoints(
597 aPad->GetSize(), aPad->GetOrientation(), ovalKeyPointFlags );
598
599 for ( const VECTOR2I& pt: oval_pts ) {
600 // Transform to the pad positon
601 addAnchor( pos + pt, OUTLINE | SNAPPABLE, aPad );
602 }
603 break;
604 }
605
606 case PAD_SHAPE::RECTANGLE:
607 case PAD_SHAPE::TRAPEZOID:
608 case PAD_SHAPE::ROUNDRECT:
609 case PAD_SHAPE::CHAMFERED_RECT:
610 {
611 VECTOR2I half_size( aPad->GetSize() / 2 );
612 VECTOR2I trap_delta( 0, 0 );
613
614 if( aPad->GetShape() == PAD_SHAPE::TRAPEZOID )
615 trap_delta = aPad->GetDelta() / 2;
616
617 SHAPE_LINE_CHAIN corners;
618
619 corners.Append( -half_size.x - trap_delta.y, half_size.y + trap_delta.x );
620 corners.Append( half_size.x + trap_delta.y, half_size.y - trap_delta.x );
621 corners.Append( half_size.x - trap_delta.y, -half_size.y + trap_delta.x );
622 corners.Append( -half_size.x + trap_delta.y, -half_size.y - trap_delta.x );
623 corners.SetClosed( true );
624
625 corners.Rotate( aPad->GetOrientation() );
626 corners.Move( aPad->ShapePos() );
627
628 for( size_t ii = 0; ii < corners.GetSegmentCount(); ++ii )
629 {
630 const SEG& seg = corners.GetSegment( ii );
631 addAnchor( seg.A, OUTLINE | SNAPPABLE, aPad );
632 addAnchor( seg.Center(), OUTLINE | SNAPPABLE, aPad );
633
634 if( ii == corners.GetSegmentCount() - 1 )
635 addAnchor( seg.B, OUTLINE | SNAPPABLE, aPad );
636 }
637
638 break;
639 }
640
641 default:
642 {
643 const auto& outline = aPad->GetEffectivePolygon( ERROR_INSIDE );
644
645 if( !outline->IsEmpty() )
646 {
647 for( const VECTOR2I& pt : outline->Outline( 0 ).CPoints() )
648 addAnchor( pt, OUTLINE | SNAPPABLE, aPad );
649 }
650
651 break;
652 }
653 }
654
655 if (aPad->HasHole()) {
656
657 // Holes are at the pad centre (it's the shape that may be offset)
658 const VECTOR2I hole_pos = aPad->GetPosition();
659 const VECTOR2I hole_size = aPad->GetDrillSize();
660
661 std::vector<VECTOR2I> snap_pts;
662
663 if ( hole_size.x == hole_size.y )
664 {
665 // Circle
666 snap_pts = getCircleKeyPoints( hole_size.x / 2 );
667 }
668 else
669 {
670 // Oval
671
672 // For now there's no way to have an off-angle hole, so this is the
673 // same as the pad. In future, this may not be true:
674 // https://gitlab.com/kicad/code/kicad/-/issues/4124
675 const EDA_ANGLE hole_orientation = aPad->GetOrientation();
676 snap_pts = GetOvalKeyPoints( hole_size, hole_orientation, ovalKeyPointFlags );
677 }
678
679 for (const auto& snap_pt : snap_pts)
680 {
681 addAnchor( hole_pos + snap_pt, OUTLINE | SNAPPABLE, aPad );
682 }
683 }
684 };
685
686 auto handleShape =
687 [&]( PCB_SHAPE* shape )
688 {
689 VECTOR2I start = shape->GetStart();
690 VECTOR2I end = shape->GetEnd();
691
692 switch( shape->GetShape() )
693 {
694 case SHAPE_T::CIRCLE:
695 {
696 int r = ( start - end ).EuclideanNorm();
697
698 addAnchor( start, ORIGIN | SNAPPABLE, shape );
699 addAnchor( start + VECTOR2I( -r, 0 ), OUTLINE | SNAPPABLE, shape );
700 addAnchor( start + VECTOR2I( r, 0 ), OUTLINE | SNAPPABLE, shape );
701 addAnchor( start + VECTOR2I( 0, -r ), OUTLINE | SNAPPABLE, shape );
702 addAnchor( start + VECTOR2I( 0, r ), OUTLINE | SNAPPABLE, shape );
703 break;
704 }
705
706 case SHAPE_T::ARC:
707 addAnchor( shape->GetStart(), CORNER | SNAPPABLE, shape );
708 addAnchor( shape->GetEnd(), CORNER | SNAPPABLE, shape );
709 addAnchor( shape->GetArcMid(), CORNER | SNAPPABLE, shape );
710 addAnchor( shape->GetCenter(), ORIGIN | SNAPPABLE, shape );
711 break;
712
713 case SHAPE_T::RECTANGLE:
714 {
715 VECTOR2I point2( end.x, start.y );
716 VECTOR2I point3( start.x, end.y );
717 SEG first( start, point2 );
718 SEG second( point2, end );
719 SEG third( end, point3 );
720 SEG fourth( point3, start );
721
722 addAnchor( first.A, CORNER | SNAPPABLE, shape );
723 addAnchor( first.Center(), CORNER | SNAPPABLE, shape );
724 addAnchor( second.A, CORNER | SNAPPABLE, shape );
725 addAnchor( second.Center(), CORNER | SNAPPABLE, shape );
726 addAnchor( third.A, CORNER | SNAPPABLE, shape );
727 addAnchor( third.Center(), CORNER | SNAPPABLE, shape );
728 addAnchor( fourth.A, CORNER | SNAPPABLE, shape );
729 addAnchor( fourth.Center(), CORNER | SNAPPABLE, shape );
730 break;
731 }
732
733 case SHAPE_T::SEGMENT:
734 addAnchor( start, CORNER | SNAPPABLE, shape );
735 addAnchor( end, CORNER | SNAPPABLE, shape );
736 addAnchor( shape->GetCenter(), CORNER | SNAPPABLE, shape );
737 break;
738
739 case SHAPE_T::POLY:
740 {
742 lc.SetClosed( true );
743 std::vector<VECTOR2I> poly;
744 shape->DupPolyPointsList( poly );
745
746 for( const VECTOR2I& p : poly )
747 {
748 addAnchor( p, CORNER | SNAPPABLE, shape );
749 lc.Append( p );
750 }
751
752 addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
753 break;
754 }
755
756 case SHAPE_T::BEZIER:
757 addAnchor( start, CORNER | SNAPPABLE, shape );
758 addAnchor( end, CORNER | SNAPPABLE, shape );
760
761 default:
762 addAnchor( shape->GetPosition(), ORIGIN | SNAPPABLE, shape );
763 break;
764 }
765 };
766
767 switch( aItem->Type() )
768 {
769 case PCB_FOOTPRINT_T:
770 {
771 FOOTPRINT* footprint = static_cast<FOOTPRINT*>( aItem );
772
773 for( PAD* pad : footprint->Pads() )
774 {
775 if( aFrom )
776 {
777 if( aSelectionFilter && !aSelectionFilter->pads )
778 continue;
779 }
780 else
781 {
782 if( m_magneticSettings->pads != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
783 continue;
784 }
785
786 if( !view->IsVisible( pad ) || !pad->GetBoundingBox().Contains( aRefPos ) )
787 continue;
788
789 // Getting pads from a footprint requires re-checking that the pads are shown
790 bool onActiveLayer = !isHighContrast;
791 bool isLODVisible = false;
792
793 for( PCB_LAYER_ID layer : pad->GetLayerSet().Seq() )
794 {
795 if( !onActiveLayer && activeLayers.count( layer ) )
796 onActiveLayer = true;
797
798 if( !isLODVisible && pad->ViewGetLOD( layer, view ) < view->GetScale() )
799 isLODVisible = true;
800
801 if( onActiveLayer && isLODVisible )
802 {
803 handlePadShape( pad );
804 break;
805 }
806 }
807 }
808
809 if( aFrom && aSelectionFilter && !aSelectionFilter->footprints )
810 break;
811
812 // if the cursor is not over a pad, then drag the footprint by its origin
813 VECTOR2I position = footprint->GetPosition();
814 addAnchor( position, ORIGIN | SNAPPABLE, footprint );
815
816 // Add the footprint center point if it is markedly different from the origin
817 VECTOR2I center = footprint->GetBoundingBox( false, false ).Centre();
818 VECTOR2I grid( GetGrid() );
819
820 if( ( center - position ).SquaredEuclideanNorm() > grid.SquaredEuclideanNorm() )
821 addAnchor( center, ORIGIN | SNAPPABLE, footprint );
822
823 break;
824 }
825
826 case PCB_PAD_T:
827 if( aFrom )
828 {
829 if( aSelectionFilter && !aSelectionFilter->pads )
830 break;
831 }
832 else
833 {
834 if( m_magneticSettings->pads != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
835 break;
836 }
837
838 handlePadShape( static_cast<PAD*>( aItem ) );
839
840 break;
841
842 case PCB_TEXTBOX_T:
843 if( aFrom )
844 {
845 if( aSelectionFilter && !aSelectionFilter->text )
846 break;
847 }
848 else
849 {
851 break;
852 }
853
854 handleShape( static_cast<PCB_SHAPE*>( aItem ) );
855 break;
856
857 case PCB_SHAPE_T:
858 if( aFrom )
859 {
860 if( aSelectionFilter && !aSelectionFilter->graphics )
861 break;
862 }
863 else
864 {
866 break;
867 }
868
869 handleShape( static_cast<PCB_SHAPE*>( aItem ) );
870 break;
871
872 case PCB_TRACE_T:
873 case PCB_ARC_T:
874 {
875 if( aFrom )
876 {
877 if( aSelectionFilter && !aSelectionFilter->tracks )
878 break;
879 }
880 else
881 {
882 if( m_magneticSettings->tracks != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
883 break;
884 }
885
886 PCB_TRACK* track = static_cast<PCB_TRACK*>( aItem );
887
888 addAnchor( track->GetStart(), CORNER | SNAPPABLE, track );
889 addAnchor( track->GetEnd(), CORNER | SNAPPABLE, track );
890 addAnchor( track->GetCenter(), ORIGIN, track);
891
892 break;
893 }
894
895 case PCB_MARKER_T:
896 case PCB_TARGET_T:
897 addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
898 break;
899
900 case PCB_VIA_T:
901 if( aFrom )
902 {
903 if( aSelectionFilter && !aSelectionFilter->vias )
904 break;
905 }
906 else
907 {
908 if( m_magneticSettings->tracks != MAGNETIC_OPTIONS::CAPTURE_ALWAYS )
909 break;
910 }
911
912 addAnchor( aItem->GetPosition(), ORIGIN | CORNER | SNAPPABLE, aItem );
913
914 break;
915
916 case PCB_ZONE_T:
917 {
918 if( aFrom && aSelectionFilter && !aSelectionFilter->zones )
919 break;
920
921 const SHAPE_POLY_SET* outline = static_cast<const ZONE*>( aItem )->Outline();
922
924 lc.SetClosed( true );
925
926 for( auto iter = outline->CIterateWithHoles(); iter; iter++ )
927 {
928 addAnchor( *iter, CORNER | SNAPPABLE, aItem );
929 lc.Append( *iter );
930 }
931
932 addAnchor( lc.NearestPoint( aRefPos ), OUTLINE, aItem );
933
934 break;
935 }
936
939 {
940 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
941 break;
942
943 const PCB_DIM_ALIGNED* dim = static_cast<const PCB_DIM_ALIGNED*>( aItem );
944 addAnchor( dim->GetCrossbarStart(), CORNER | SNAPPABLE, aItem );
945 addAnchor( dim->GetCrossbarEnd(), CORNER | SNAPPABLE, aItem );
946 addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
947 addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
948 break;
949 }
950
951 case PCB_DIM_CENTER_T:
952 {
953 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
954 break;
955
956 const PCB_DIM_CENTER* dim = static_cast<const PCB_DIM_CENTER*>( aItem );
957 addAnchor( dim->GetStart(), CORNER | SNAPPABLE, aItem );
958 addAnchor( dim->GetEnd(), CORNER | SNAPPABLE, aItem );
959
960 VECTOR2I start( dim->GetStart() );
961 VECTOR2I radial( dim->GetEnd() - dim->GetStart() );
962
963 for( int i = 0; i < 2; i++ )
964 {
965 RotatePoint( radial, -ANGLE_90 );
966 addAnchor( start + radial, CORNER | SNAPPABLE, aItem );
967 }
968
969 break;
970 }
971
972 case PCB_DIM_RADIAL_T:
973 {
974 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
975 break;
976
977 const PCB_DIM_RADIAL* radialDim = static_cast<const PCB_DIM_RADIAL*>( aItem );
978 addAnchor( radialDim->GetStart(), CORNER | SNAPPABLE, aItem );
979 addAnchor( radialDim->GetEnd(), CORNER | SNAPPABLE, aItem );
980 addAnchor( radialDim->GetKnee(), CORNER | SNAPPABLE, aItem );
981 addAnchor( radialDim->GetTextPos(), CORNER | SNAPPABLE, aItem );
982 break;
983 }
984
985 case PCB_DIM_LEADER_T:
986 {
987 if( aFrom && aSelectionFilter && !aSelectionFilter->dimensions )
988 break;
989
990 const PCB_DIM_LEADER* leader = static_cast<const PCB_DIM_LEADER*>( aItem );
991 addAnchor( leader->GetStart(), CORNER | SNAPPABLE, aItem );
992 addAnchor( leader->GetEnd(), CORNER | SNAPPABLE, aItem );
993 addAnchor( leader->GetTextPos(), CORNER | SNAPPABLE, aItem );
994 break;
995 }
996
997 case PCB_FIELD_T:
998 case PCB_TEXT_T:
999 if( aFrom && aSelectionFilter && !aSelectionFilter->text )
1000 break;
1001
1002 addAnchor( aItem->GetPosition(), ORIGIN, aItem );
1003 break;
1004
1005 case PCB_GROUP_T:
1006 {
1007 const PCB_GROUP* group = static_cast<const PCB_GROUP*>( aItem );
1008
1009 for( BOARD_ITEM* item : group->GetItems() )
1010 computeAnchors( item, aRefPos, aFrom );
1011
1012 break;
1013 }
1014
1015 default:
1016 break;
1017 }
1018}
1019
1020
1022 LSET aMatchLayers )
1023{
1024 double minDist = std::numeric_limits<double>::max();
1025 ANCHOR* best = nullptr;
1026
1027 for( ANCHOR& a : m_anchors )
1028 {
1029 BOARD_ITEM* item = static_cast<BOARD_ITEM*>( a.item );
1030
1031 if( !m_magneticSettings->allLayers && ( ( aMatchLayers & item->GetLayerSet() ) == 0 ) )
1032 continue;
1033
1034 if( ( aFlags & a.flags ) != aFlags )
1035 continue;
1036
1037 double dist = a.Distance( aPos );
1038
1039 if( dist < minDist )
1040 {
1041 minDist = dist;
1042 best = &a;
1043 }
1044 }
1045
1046 return best;
1047}
constexpr EDA_IU_SCALE pcbIUScale
Definition: base_units.h:108
WINDOW_SETTINGS m_Window
Definition: app_settings.h:170
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:77
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:248
virtual LSET GetLayerSet() const
Return a std::bitset of all layers on which the item physically resides.
Definition: board_item.h:231
virtual void RunOnDescendants(const std::function< void(BOARD_ITEM *)> &aFunction, int aDepth=0) const
Invoke a function on all descendants.
Definition: board_item.h:201
void SetOrigin(const Vec &pos)
Definition: box2.h:203
Vec Centre() const
Definition: box2.h:71
void SetEnd(coord_type x, coord_type y)
Definition: box2.h:256
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:88
virtual VECTOR2I GetPosition() const
Definition: eda_item.h:242
KICAD_T Type() const
Returns the type of object.
Definition: eda_item.h:100
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:215
const VECTOR2I & GetTextPos() const
Definition: eda_text.h:234
PADS & Pads()
Definition: footprint.h:191
VECTOR2I GetPosition() const override
Definition: footprint.h:209
const BOX2I GetBoundingBox() const override
Return the orthogonal bounding box of this object for display purposes.
Definition: footprint.cpp:1222
VECTOR2I m_skipPoint
Definition: grid_helper.h:182
bool m_enableGrid
Definition: grid_helper.h:178
TOOL_MANAGER * m_toolMgr
Definition: grid_helper.h:172
VECTOR2D GetVisibleGrid() const
Definition: grid_helper.cpp:61
VECTOR2I GetGrid() const
Definition: grid_helper.cpp:53
ANCHOR * m_snapItem
Definition: grid_helper.h:180
bool m_enableSnapLine
Definition: grid_helper.h:179
bool m_enableSnap
Definition: grid_helper.h:177
void addAnchor(const VECTOR2I &aPos, int aFlags, EDA_ITEM *aItem)
Definition: grid_helper.h:148
void clearAnchors()
Definition: grid_helper.h:154
KIGFX::ORIGIN_VIEWITEM m_viewSnapPoint
Definition: grid_helper.h:184
KIGFX::ORIGIN_VIEWITEM m_viewSnapLine
Definition: grid_helper.h:185
KIGFX::ORIGIN_VIEWITEM m_viewAxis
Definition: grid_helper.h:186
std::vector< ANCHOR > m_anchors
Definition: grid_helper.h:170
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
const VECTOR2D & GetGridSize() const
Return the grid size.
double GetWorldScale() const
Get the world scale.
void SetPosition(const VECTOR2I &aPosition) override
void SetColor(const KIGFX::COLOR4D &aColor)
VECTOR2I GetPosition() const override
void SetStyle(MARKER_STYLE aStyle)
void SetSize(int aSize)
void SetDrawAtZero(bool aDrawFlag)
Set the draw at zero flag.
void SetEndPosition(const VECTOR2D &aPosition)
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const std::set< int > GetHighContrastLayers() const
Returns the set of currently high-contrast layers.
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
bool GetHighContrast() const
virtual double ViewGetLOD(int aLayer, VIEW *aView) const
Return the level of detail (LOD) of the item.
Definition: view_item.h:141
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:271
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition: view.cpp:315
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition: view.cpp:354
virtual int Query(const BOX2I &aRect, std::vector< LAYER_ITEM_PAIR > &aResult) const
Find all visible items that touch or are within the rectangle aRect.
Definition: view.cpp:426
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:1639
GAL * GetGAL() const
Return the #GAL this view is using to draw graphical primitives.
Definition: view.h:197
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition: view.h:215
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition: view.cpp:1609
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition: view.cpp:1566
LSET is a set of PCB_LAYER_IDs.
Definition: layer_ids.h:574
static LSET AllLayersMask()
Definition: lset.cpp:898
Definition: pad.h:59
virtual const VECTOR2I & GetStart() const
The dimension's origin is the first feature point for the dimension.
virtual const VECTOR2I & GetEnd() const
For better understanding of the points that make a dimension:
const VECTOR2I & GetCrossbarStart() const
const VECTOR2I & GetCrossbarEnd() const
Mark the center of a circle or arc with a cross shape.
A leader is a dimension-like object pointing to a specific point.
A radial dimension indicates either the radius or diameter of an arc or circle.
VECTOR2I GetKnee() const
void computeAnchors(BOARD_ITEM *aItem, const VECTOR2I &aRefPos, bool aFrom=false, const PCB_SELECTION_FILTER_OPTIONS *aSelectionFilter=nullptr)
computeAnchors inserts the local anchor points in to the grid helper for the specified board item,...
~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)
std::set< BOARD_ITEM * > queryVisible(const BOX2I &aArea, const std::vector< BOARD_ITEM * > &aSkip) const
ANCHOR * nearestAnchor(const VECTOR2I &aPos, int aFlags, LSET aMatchLayers)
MAGNETIC_SETTINGS * m_magneticSettings
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:60
PCB_GRID_HELPER(TOOL_MANAGER *aToolMgr, MAGNETIC_SETTINGS *aMagneticSettings)
VECTOR2I AlignToNearestPad(const VECTOR2I &aMousePos, PADS &aPads)
A set of BOARD_ITEMs (i.e., without duplicates).
Definition: pcb_group.h:51
bool IsFootprintEditor() const
const VECTOR2I & GetStart() const
Definition: pcb_track.h:113
const VECTOR2I & GetEnd() const
Definition: pcb_track.h:110
Definition: seg.h:42
VECTOR2I A
Definition: seg.h:49
ecoord SquaredDistance(const SEG &aSeg) const
Definition: seg.cpp:75
VECTOR2I::extended_type ecoord
Definition: seg.h:44
VECTOR2I B
Definition: seg.h:50
VECTOR2I Center() const
Definition: seg.h:362
OPT_VECTOR2I IntersectLines(const SEG &aSeg) const
Compute the intersection point of lines passing through ends of (this) and aSeg.
Definition: seg.h:210
const VECTOR2I & GetP1() const
Definition: shape_arc.h:113
int IntersectLine(const SEG &aSeg, std::vector< VECTOR2I > *aIpsBuffer) const
Find intersection points between this arc and aSeg, treating aSeg as an infinite line.
Definition: shape_arc.cpp:279
const VECTOR2I & GetP0() const
Definition: shape_arc.h:112
Represent a polyline containing arcs as well as line segments: A chain of connected line and/or arc s...
void Move(const VECTOR2I &aVector) override
void SetClosed(bool aClosed)
Mark the line chain as closed (i.e.
void Append(int aX, int aY, bool aAllowDuplication=false)
Append a new point at the end of the line chain.
void Rotate(const EDA_ANGLE &aAngle, const VECTOR2I &aCenter={ 0, 0 }) override
Rotate all vertices by a given angle.
virtual const SEG GetSegment(int aIndex) const override
const VECTOR2I NearestPoint(const VECTOR2I &aP, bool aAllowInternalShapePoints=true) const
Find a point on the line chain that is closest to point aP.
virtual size_t GetSegmentCount() const override
Represent a set of closed polygons.
CONST_ITERATOR CIterateWithHoles(int aOutline) const
Master controller class:
Definition: tool_manager.h:57
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:416
APP_SETTINGS_BASE * GetSettings() const
Definition: tool_manager.h:395
KIGFX::VIEW * GetView() const
Definition: tool_manager.h:386
static constexpr extended_type ECOORD_MAX
Definition: vector2d.h:75
Handle a list of polygons defining a copper zone.
Definition: zone.h:72
static constexpr EDA_ANGLE ANGLE_90
Definition: eda_angle.h:437
@ ERROR_INSIDE
GRID_HELPER_GRIDS
Definition: grid_helper.h:37
@ GRID_VIAS
Definition: grid_helper.h:43
@ GRID_TEXT
Definition: grid_helper.h:44
@ GRID_CURRENT
Definition: grid_helper.h:39
@ GRID_GRAPHICS
Definition: grid_helper.h:45
@ GRID_CONNECTABLE
Definition: grid_helper.h:41
@ GRID_WIRES
Definition: grid_helper.h:42
bool IsPcbLayer(int aLayer)
Test whether a layer is a valid layer for Pcbnew.
Definition: layer_ids.h:869
@ LAYER_AUX_ITEMS
Auxiliary items (guides, rule, etc)
Definition: layer_ids.h:226
@ LAYER_ANCHOR
anchor of items having an anchor point (texts, footprints)
Definition: layer_ids.h:205
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
@ GEOMETRY
Position or shape has changed.
Definition: view_item.h:54
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:424
unsigned int OVAL_KEY_POINT_FLAGS
Definition: oval.h:43
@ OVAL_CARDINAL_EXTREMES
Definition: oval.h:39
@ OVAL_CAP_TIPS
Definition: oval.h:35
@ OVAL_SIDE_MIDPOINTS
Definition: oval.h:37
@ OVAL_CENTER
Definition: oval.h:34
std::vector< VECTOR2I > GetOvalKeyPoints(const VECTOR2I &aOvalSize, const EDA_ANGLE &aRotation, OVAL_KEY_POINT_FLAGS aFlags)
Get a list of interesting points on an oval (rectangle with semicircular end caps)
Definition: oval.cpp:31
Class to handle a set of BOARD_ITEMs.
std::optional< VECTOR2I > OPT_VECTOR2I
Definition: seg.h:39
double Distance(const VECTOR2I &aP) const
Definition: grid_helper.h:142
MAGNETIC_OPTIONS tracks
MAGNETIC_OPTIONS pads
This file contains data structures that are saved in the project file or project local settings file ...
bool graphics
Graphic lines, shapes, polygons.
bool 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:228
double EuclideanNorm(const VECTOR2I &vector)
Definition: trigo.h:128
@ 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
constexpr ret_type KiROUND(fp_type v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: util.h:85
VECTOR2< double > VECTOR2D
Definition: vector2d.h:587
VECTOR2< int > VECTOR2I
Definition: vector2d.h:588