KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include "tool/grid_helper.h"
21
22#include <array>
23#include <functional>
24#include <cmath>
25#include <limits>
26#include <numbers>
27
28#include <advanced_config.h>
29#include <trace_helpers.h>
30#include <wx/log.h>
32#include <math/util.h> // for KiROUND
33#include <math/vector2d.h>
34#include <tool/tool_manager.h>
35#include <tool/tools_holder.h>
36#include <view/view.h>
38#include <gal/painter.h>
39
40
43{
45 m_enableSnap = true;
46 m_enableSnapLine = true;
47 m_enableGrid = true;
48 m_snapItem = std::nullopt;
49
50 // Default-constructing the point would park it on the origin and suppress snapping there
52
53 m_manualGrid = VECTOR2D( 1, 1 );
55 m_manualOrigin = VECTOR2I( 0, 0 );
57}
58
59
60GRID_HELPER::GRID_HELPER( TOOL_MANAGER* aToolMgr, int aConstructionLayer ) :
62{
63 m_toolMgr = aToolMgr;
64
65 if( !m_toolMgr )
66 return;
67
68 KIGFX::VIEW* view = m_toolMgr->GetView();
69 KIGFX::RENDER_SETTINGS* settings = view->GetPainter()->GetSettings();
70 KIGFX::COLOR4D constructionColor = settings->GetLayerColor( aConstructionLayer );
71
72 m_constructionGeomPreview.SetColor( constructionColor );
73 m_constructionGeomPreview.SetPersistentColor( constructionColor );
74
77
78 m_snapManager.SetUpdateCallback(
79 [view, this]( bool aAnythingShown )
80 {
81 const bool currentlyVisible = view->IsVisible( &m_constructionGeomPreview );
82
83 if( currentlyVisible && aAnythingShown )
84 {
86 }
87 else
88 {
89 view->SetVisible( &m_constructionGeomPreview, aAnythingShown );
90 }
91
92 // Headless tests and benchmarks have a view but no canvas holder.
93 if( TOOLS_HOLDER* holder = m_toolMgr->GetToolHolder() )
94 holder->RefreshCanvas();
95 } );
96
97 // Initialise manual values from view for compatibility
98 m_manualGrid = view->GetGAL()->GetGridSize();
99 m_manualVisibleGrid = view->GetGAL()->GetVisibleGridSize();
102}
103
104
106{
107 if( !m_toolMgr )
108 return;
109
110 KIGFX::VIEW& view = *m_toolMgr->GetView();
113 if( m_anchorDebug )
114 view.Remove( m_anchorDebug.get() );
117
119{
120 static bool permitted = ADVANCED_CFG::GetCfg().m_EnableSnapAnchorsDebug;
121
122 if( !m_toolMgr )
123 return nullptr;
124
125 if( permitted && !m_anchorDebug )
126 {
127 KIGFX::VIEW& view = *m_toolMgr->GetView();
128 m_anchorDebug = std::make_unique<KIGFX::ANCHOR_DEBUG>();
129 view.Add( m_anchorDebug.get() );
130 view.SetVisible( m_anchorDebug.get(), true );
131 }
132
133 return m_anchorDebug.get();
134}
135
136
138{
139 if( m_toolMgr )
140 m_toolMgr->GetView()->SetVisible( &m_constructionGeomPreview, aShow );
141}
142
143
144void GRID_HELPER::SetSnapLineDirections( const std::vector<VECTOR2I>& aDirections )
145{
146 m_snapManager.GetSnapLineManager().SetDirections( aDirections );
147}
148
149
151{
152 m_snapManager.GetSnapLineManager().SetSnapLineOrigin( aOrigin );
153}
154
155void GRID_HELPER::SetSnapLineEnd( const std::optional<VECTOR2I>& aEnd )
156{
157 m_snapManager.GetSnapLineManager().SetSnapLineEnd( aEnd );
158}
159
161{
162 m_snapManager.GetSnapLineManager().ClearSnapLine();
163}
164
165
167{
168 std::vector<SEG> dimensionBrackets;
169 const SNAP_GUIDE* snapLine = nullptr;
170
171 for( const SNAP_GUIDE& guide : aResult.guides )
172 {
174 {
175 dimensionBrackets.emplace_back( guide.start, guide.end );
176 wxLogTrace( wxT( "KICAD_SNAP_RESOLVER" ), "bracket axis=%c start=(%d,%d) end=(%d,%d)",
177 guide.start.x == guide.end.x ? 'y' : 'x', guide.start.x, guide.start.y, guide.end.x,
178 guide.end.y );
179 }
180 else if( !snapLine )
181 {
182 snapLine = &guide;
183 }
184 }
185
186 m_snapManager.SetDimensionBrackets( std::move( dimensionBrackets ) );
187
188 if( snapLine )
189 {
190 SNAP_LINE_MANAGER& manager = m_snapManager.GetSnapLineManager();
191 manager.SetSnapLineOrigin( snapLine->start );
192 manager.SetSnapLineEnd( snapLine->end );
193 }
194}
195
196
198 bool aAnchorPoint )
199{
200 if( aAnchorPoint )
201 return { SNAP_REFERENCE_KIND::ANCHOR_POINT, -1, -1 };
202
203 const std::array<int, 3> xFeatures = { aBounds.GetLeft(), aBounds.Centre().x, aBounds.GetRight() };
204 const std::array<int, 3> yFeatures = { aBounds.GetTop(), aBounds.Centre().y, aBounds.GetBottom() };
205 const auto nearestFeature = []( int aCoordinate, const std::array<int, 3>& aFeatures )
206 {
207 int best = 0;
208
209 for( int index = 1; index < 3; ++index )
210 {
211 if( std::abs( aCoordinate - aFeatures[index] ) < std::abs( aCoordinate - aFeatures[best] ) )
212 {
213 best = index;
214 }
215 }
216
217 return best;
218 };
219
220 return { SNAP_REFERENCE_KIND::BOUNDS_FEATURE, nearestFeature( aPoint.x, xFeatures ),
221 nearestFeature( aPoint.y, yFeatures ) };
222}
223
224
225void GRID_HELPER::setLayoutReference( const VECTOR2I& aPoint, const std::optional<BOX2I>& aBounds, bool aAnchorPoint )
226{
227 if( aBounds )
228 m_layoutReferencePreference = classifyReference( aPoint, *aBounds, aAnchorPoint );
229 else
231
232 const char* referenceKind = "none";
233
235 referenceKind = "bounds";
237 referenceKind = "anchor-point";
238
239 wxLogTrace( wxT( "KICAD_SNAP_RESOLVER" ), "drag reference kind=%s x-feature=%d y-feature=%d", referenceKind,
240 m_layoutReferencePreference.horizontalFeature, m_layoutReferencePreference.verticalFeature );
241}
242
243
244std::optional<VECTOR2I> GRID_HELPER::SnapToConstructionLines( const VECTOR2I& aPoint, const VECTOR2I& aNearestGrid,
245 const VECTOR2D& aGrid, double aSnapRange ) const
246{
247 const SNAP_LINE_MANAGER& snapLineManager = m_snapManager.GetSnapLineManager();
248 const OPT_VECTOR2I& snapOrigin = snapLineManager.GetSnapLineOrigin();
249
250 wxLogTrace( traceSnap, "SnapToConstructionLines: aPoint=(%d, %d), nearestGrid=(%d, %d), snapRange=%.1f", aPoint.x,
251 aPoint.y, aNearestGrid.x, aNearestGrid.y, aSnapRange );
252
253 if( !snapOrigin || snapLineManager.GetDirections().empty() )
254 {
255 wxLogTrace( traceSnap, " No snap origin or no directions, returning nullopt" );
256 return std::nullopt;
257 }
258
259 const VECTOR2I& origin = *snapOrigin;
260
261 wxLogTrace( traceSnap, " snapOrigin=(%d, %d), directions count=%zu",
262 origin.x, origin.y, snapLineManager.GetDirections().size() );
263
264 const std::vector<VECTOR2I>& directions = snapLineManager.GetDirections();
265 const std::optional<int> activeDirection = snapLineManager.GetActiveDirection();
266
267 if( activeDirection )
268 wxLogTrace( traceSnap, " activeDirection=%d", *activeDirection );
269
270 const VECTOR2D originVec( origin );
271 const VECTOR2D cursorVec( aPoint );
272 const VECTOR2D delta = cursorVec - originVec;
273
274 std::optional<VECTOR2I> bestPoint;
275 double bestPerp = std::numeric_limits<double>::max();
276 double bestDistance = std::numeric_limits<double>::max();
277
278 for( size_t ii = 0; ii < directions.size(); ++ii )
279 {
280 const VECTOR2I& dir = directions[ii];
281 VECTOR2D dirVector( dir );
282 double dirLength = dirVector.EuclideanNorm();
283
284 if( dirLength == 0.0 )
285 {
286 wxLogTrace( traceSnap, " Direction %zu: zero length, skipping", ii );
287 continue;
288 }
289
290 VECTOR2D dirUnit = dirVector / dirLength;
291
292 double distanceAlong = delta.Dot( dirUnit );
293 VECTOR2D projection = originVec + dirUnit * distanceAlong;
294 VECTOR2D offset = delta - dirUnit * distanceAlong;
295 double perpDistance = offset.EuclideanNorm();
296
297 double snapThreshold = aSnapRange;
298
299 if( activeDirection && *activeDirection == static_cast<int>( ii ) )
300 {
301 snapThreshold *= 1.5;
302 wxLogTrace( traceSnap, " Direction %zu: ACTIVE, increased snapThreshold=%.1f", ii, snapThreshold );
303 }
304
305 wxLogTrace( traceSnap, " Direction %zu: dir=(%d, %d), perpDist=%.1f, threshold=%.1f",
306 ii, dir.x, dir.y, perpDistance, snapThreshold );
307
308 if( perpDistance > snapThreshold )
309 {
310 wxLogTrace( traceSnap, " perpDistance > threshold, skipping" );
311 continue;
312 }
313
314 VECTOR2D candidate = projection;
315
316 if( canUseGrid() )
317 {
318 if( dir.x == 0 && dir.y != 0 )
319 {
320 // Vertical construction line: snap to grid intersection
321 candidate.x = origin.x;
322 candidate.y = aNearestGrid.y;
323 wxLogTrace( traceSnap, " Vertical snap: candidate=(%d, %d)", (int) candidate.x,
324 (int) candidate.y );
325 }
326 else if( dir.y == 0 && dir.x != 0 )
327 {
328 // Horizontal construction line: snap to grid intersection
329 candidate.x = aNearestGrid.x;
330 candidate.y = origin.y;
331 wxLogTrace( traceSnap, " Horizontal snap: candidate=(%d, %d)", (int) candidate.x,
332 (int) candidate.y );
333 }
334 else
335 {
336 // Diagonal construction line: find nearest grid intersection along the line
337 // We need to find grid points near the projection point and pick the closest
338 // one that lies on the construction line
339
340 // Get the grid origin for proper alignment
341 VECTOR2D gridOrigin( GetOrigin() );
342
343 // Calculate the projection point relative to grid
344 VECTOR2D relProjection = projection - gridOrigin;
345
346 // Find nearby grid points (check 9 points in a 3x3 grid around the projection)
347 std::vector<VECTOR2D> gridPoints;
348 for( int dx = -1; dx <= 1; ++dx )
349 {
350 for( int dy = -1; dy <= 1; ++dy )
351 {
352 double gridX = std::round( relProjection.x / aGrid.x ) * aGrid.x + dx * aGrid.x;
353 double gridY = std::round( relProjection.y / aGrid.y ) * aGrid.y + dy * aGrid.y;
354 gridPoints.push_back( VECTOR2D( gridX + gridOrigin.x, gridY + gridOrigin.y ) );
355 }
356 }
357
358 // Find the grid point closest to the construction line
359 double bestGridDist = std::numeric_limits<double>::max();
360 VECTOR2D bestGridPt = projection;
361
362 for( const VECTOR2D& gridPt : gridPoints )
363 {
364 // Calculate perpendicular distance from grid point to construction line
365 VECTOR2D gridDelta = gridPt - originVec;
366 double gridDistAlong = gridDelta.Dot( dirUnit );
367 VECTOR2D gridProjection = originVec + dirUnit * gridDistAlong;
368 double gridPerpDist = ( gridPt - gridProjection ).EuclideanNorm();
369
370 // Also consider distance from cursor
371 double distFromCursor = ( gridPt - cursorVec ).EuclideanNorm();
372
373 // Prefer grid points that are close to the line and close to cursor
374 double score = gridPerpDist + distFromCursor * 0.1;
375
376 if( score < bestGridDist )
377 {
378 bestGridDist = score;
379 bestGridPt = gridPt;
380 }
381 }
382
383 candidate = bestGridPt;
384 wxLogTrace( traceSnap, " Diagonal snap: candidate=(%.1f, %.1f), perpDist=%.1f",
385 candidate.x, candidate.y, bestGridDist );
386 }
387 }
388 else
389 {
390 wxLogTrace( traceSnap, " Grid disabled, using projection candidate=(%.1f, %.1f)",
391 candidate.x, candidate.y );
392 }
393
394 VECTOR2I candidateInt = KiROUND( candidate );
395
396 if( candidateInt == m_skipPoint )
397 {
398 wxLogTrace( traceSnap, " candidateInt matches m_skipPoint, skipping" );
399 continue;
400 }
401
402 VECTOR2D candidateDelta( candidateInt.x - aPoint.x, candidateInt.y - aPoint.y );
403 double candidateDistance = candidateDelta.EuclideanNorm();
404
405 wxLogTrace( traceSnap, " candidateInt=(%d, %d), candidateDist=%.1f",
406 candidateInt.x, candidateInt.y, candidateDistance );
407
408 if( perpDistance < bestPerp
409 || ( std::abs( perpDistance - bestPerp ) < 1e-9 && candidateDistance < bestDistance ) )
410 {
411 wxLogTrace( traceSnap, " NEW BEST: perpDist=%.1f, candDist=%.1f", perpDistance, candidateDistance );
412 bestPerp = perpDistance;
413 bestDistance = candidateDistance;
414 bestPoint = candidateInt;
415 }
416 }
417
418 if( bestPoint )
419 {
420 wxLogTrace( traceSnap, " RETURNING bestPoint=(%d, %d)", bestPoint->x, bestPoint->y );
421 }
422 else
423 {
424 wxLogTrace( traceSnap, " RETURNING nullopt (no valid snap found)" );
425 }
426
427 return bestPoint;
428}
429
430
432{
433 if( !m_toolMgr )
434 return;
435
436 m_viewSnapPoint.SetPosition( aPoint.m_point );
437 m_viewSnapPoint.SetSnapTypes( aPoint.m_types );
438
439 if( m_toolMgr->GetView()->IsVisible( &m_viewSnapPoint ) )
440 m_toolMgr->GetView()->Update( &m_viewSnapPoint, KIGFX::GEOMETRY );
441 else
442 m_toolMgr->GetView()->SetVisible( &m_viewSnapPoint, true );
443}
444
445
447{
448 VECTOR2D size = m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetGridSize() : m_manualGrid;
449 return VECTOR2I( KiROUND( size.x ), KiROUND( size.y ) );
450}
451
452
454{
455 return m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetVisibleGridSize() : m_manualVisibleGrid;
456}
457
458
460{
461 if( m_toolMgr )
462 {
463 VECTOR2D origin = m_toolMgr->GetView()->GetGAL()->GetGridOrigin();
464 return VECTOR2I( origin );
465 }
466
467 return m_manualOrigin;
468}
469
470
472{
473 GRID_HELPER_GRIDS grid = GetItemGrid( aSelection.Front() );
474
475 // Find the largest grid of all the items and use that
476 for( EDA_ITEM* item : aSelection )
477 {
478 GRID_HELPER_GRIDS itemGrid = GetItemGrid( item );
479
480 if( GetGridSize( itemGrid ) > GetGridSize( grid ) )
481 grid = itemGrid;
482 }
483
484 return grid;
485}
486
487
489{
490 return m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetGridSize() : m_manualGrid;
491}
492
493
494void GRID_HELPER::SetAuxAxes( bool aEnable, const VECTOR2I& aOrigin )
495{
496 if( aEnable )
497 {
498 m_auxAxis = aOrigin;
499 m_viewAxis.SetPosition( aOrigin );
500 if( m_toolMgr )
501 m_toolMgr->GetView()->SetVisible( &m_viewAxis, true );
502 }
503 else
504 {
505 m_auxAxis = std::optional<VECTOR2I>();
506 if( m_toolMgr )
507 m_toolMgr->GetView()->SetVisible( &m_viewAxis, false );
508 }
509}
510
511
513{
514 return computeNearest( aPoint, GetGrid(), GetOrigin() );
515}
516
517
519 const VECTOR2D& aOffset ) const
520{
521 // Round the grid size and offset rather than relying on the implicit VECTOR2D->VECTOR2I
522 // truncation in computeNearest. Grid sizes that aren't exact in IEEE 754 (e.g., 0.254mm =
523 // 10 mil) would otherwise truncate to the wrong integer (253999 instead of 254000),
524 // producing positions that aren't true grid multiples.
525 return computeNearest( aPoint, KiROUND( aGrid ), KiROUND( aOffset ) );
526}
527
528
530 const VECTOR2I& aOffset ) const
531{
532 return VECTOR2I( KiROUND( (double) ( aPoint.x - aOffset.x ) / aGrid.x ) * aGrid.x + aOffset.x,
533 KiROUND( (double) ( aPoint.y - aOffset.y ) / aGrid.y ) * aGrid.y + aOffset.y );
534}
535
536
538{
539 return Align( aPoint, GetGrid(), GetOrigin() );
540}
541
542
543VECTOR2I GRID_HELPER::Align( const VECTOR2I& aPoint, const VECTOR2D& aGrid,
544 const VECTOR2D& aOffset ) const
545{
546 if( !canUseGrid() )
547 return aPoint;
548
549 VECTOR2I nearest = AlignGrid( aPoint, aGrid, aOffset );
550
551 if( !m_auxAxis )
552 return nearest;
553
554 if( std::abs( m_auxAxis->x - aPoint.x ) < std::abs( nearest.x - aPoint.x ) )
555 nearest.x = m_auxAxis->x;
556
557 if( std::abs( m_auxAxis->y - aPoint.y ) < std::abs( nearest.y - aPoint.y ) )
558 nearest.y = m_auxAxis->y;
559
560 return nearest;
561}
562
563
565{
566 return m_enableGrid && ( m_toolMgr ? m_toolMgr->GetView()->GetGAL()->GetGridSnapping()
568}
569
570
571std::optional<VECTOR2I> GRID_HELPER::GetSnappedPoint() const
572{
573 if( m_snapItem )
574 return m_snapItem->pos;
575
576 return std::nullopt;
577}
578
579
581{
582 KIGFX::VIEW* view = m_toolMgr->GetView();
583 SNAP_RANGES ranges;
584
585 ranges.scale = view->ToWorld( SNAP_SCREEN_RADIUS );
586
587 // GetVisibleGrid().x sometimes exceeds INT_MAX, so the comparison stays in double.
588 ranges.range = KiROUND( aClampToVisibleGrid ? std::min( ranges.scale, GetVisibleGrid().x ) : ranges.scale );
589
590 const double hysteresisPixels = ADVANCED_CFG::GetCfg().m_SnapHysteresis;
591 const int hysteresisWorld = KiROUND( view->ToWorld( hysteresisPixels ) );
592
593 ranges.in = std::max( 0, ranges.range - hysteresisWorld );
594 ranges.out = ranges.range + hysteresisWorld;
595 ranges.rankingHysteresis = hysteresisPixels / SNAP_SCREEN_RADIUS;
596
597 return ranges;
598}
599
600
601void GRID_HELPER::emitAngleBranchCandidates( std::vector<SNAP_CANDIDATE>& aCandidates, const VECTOR2I& aOrigin,
602 double aSnapScale ) const
603{
604 if( !m_angleOrigin || m_angleStepDegrees <= 0.0 || aOrigin == *m_angleOrigin )
605 return;
606
607 VECTOR2D delta( aOrigin - *m_angleOrigin );
608 double step = m_angleStepDegrees * std::numbers::pi / 180.0;
609 double rawAngle = std::atan2( delta.y, delta.x );
610 int lowerBranch = static_cast<int>( std::floor( rawAngle / step ) );
611
612 for( int branch : { lowerBranch, lowerBranch + 1 } )
613 {
614 double angle = branch * step;
615 VECTOR2D direction( std::cos( angle ), std::sin( angle ) );
616 double residual = std::abs( delta.x * direction.y - delta.y * direction.x ) / aSnapScale;
617 aCandidates.push_back( SNAP_CANDIDATE::Line( { SNAP_ID_KIND::ANGLE_BRANCH, {}, 0, branch },
619 *m_angleOrigin, direction, residual ) );
620 }
621}
622
623
625{
626 static const wxString traceCategory = wxT( "KICAD_SNAP_RESOLVER" );
627 const auto callback = []( const std::string& aMessage )
628 {
629 wxLogTrace( traceCategory, "%s", aMessage.c_str() );
630 };
631
632 if( !wxLog::IsAllowedTraceMask( traceCategory ) )
633 return {};
634
635 if( !aContext.movingBounds )
636 {
637 wxLogTrace( traceCategory, "context raw=(%d,%d) reference=none bounds=none", aContext.sourcePoint.x,
638 aContext.sourcePoint.y );
639 return callback;
640 }
641
642 BOX2I projectedBounds = *aContext.movingBounds;
643
644 if( aContext.movingReferencePoint )
645 projectedBounds.Offset( aContext.sourcePoint - *aContext.movingReferencePoint );
646
647 wxLogTrace( traceCategory, "context raw=(%d,%d) reference=(%d,%d) bounds=(%d,%d,%d,%d) projected=(%d,%d,%d,%d)",
648 aContext.sourcePoint.x, aContext.sourcePoint.y,
649 aContext.movingReferencePoint ? aContext.movingReferencePoint->x : aContext.sourcePoint.x,
650 aContext.movingReferencePoint ? aContext.movingReferencePoint->y : aContext.sourcePoint.y,
651 aContext.movingBounds->GetLeft(), aContext.movingBounds->GetTop(), aContext.movingBounds->GetRight(),
652 aContext.movingBounds->GetBottom(), projectedBounds.GetLeft(), projectedBounds.GetTop(),
653 projectedBounds.GetRight(), projectedBounds.GetBottom() );
654
655 return callback;
656}
657
658
659void GRID_HELPER::emitSelfAndGridCandidates( std::vector<SNAP_CANDIDATE>& aCandidates,
660 const SNAP_SOURCE_CONTEXT& aContext, const VECTOR2I& aOrigin,
661 const VECTOR2I& aNearestGrid, double aSnapScale, int aSnapRange,
662 bool aUseGrid ) const
663{
664 const bool pointEdit = aContext.profile == SNAP_EDITOR_PROFILE::POINT_EDIT && aContext.movingItem;
665
666 if( pointEdit && aContext.stationarySourceLeg
667 && aContext.stationarySourceLeg->Distance( aOrigin ) <= aSnapRange )
668 {
670 aCandidates.push_back( SNAP_CANDIDATE::Point(
672 *aContext.stationarySourceLeg, aContext.stationarySourceLeg->Distance( aOrigin ) / aSnapScale ) );
673 }
674
675 if( pointEdit )
676 {
677 for( size_t i = 0; i < m_stationarySelfPoints.size(); ++i )
678 {
679 if( m_stationarySelfPoints[i].Distance( aOrigin ) > aSnapRange )
680 continue;
681
682 SNAP_STABLE_ID id =
683 MakeDerivedSnapId( SNAP_ID_KIND::SELF_POINT, *aContext.movingItem, static_cast<int>( i ) );
684 aCandidates.push_back( SNAP_CANDIDATE::Point(
686 m_stationarySelfPoints[i], m_stationarySelfPoints[i].Distance( aOrigin ) / aSnapScale ) );
687 }
688 }
689
690 if( aUseGrid )
691 {
694 std::abs( aNearestGrid.x - aOrigin.x ) / aSnapScale ) );
697 std::abs( aNearestGrid.y - aOrigin.y ) / aSnapScale ) );
698 }
699}
700
701
703{
704 m_stickySnapIds = aResult.accepted;
705 m_retainedAngleBranch.reset();
706
707 for( const SNAP_STABLE_ID& id : aResult.accepted )
708 {
709 if( id.kind == SNAP_ID_KIND::ANGLE_BRANCH )
710 {
712 break;
713 }
714 }
715}
int index
BOX2< VECTOR2I > BOX2I
Definition box2.h:918
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:986
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
constexpr Vec Centre() const
Definition box2.h:93
constexpr coord_type GetLeft() const
Definition box2.h:224
constexpr coord_type GetRight() const
Definition box2.h:213
constexpr coord_type GetTop() const
Definition box2.h:225
constexpr void Offset(coord_type dx, coord_type dy)
Definition box2.h:255
constexpr coord_type GetBottom() const
Definition box2.h:218
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:96
KIGFX::CONSTRUCTION_GEOM m_constructionGeomPreview
Show construction geometry (if any) on the canvas.
std::optional< VECTOR2I > m_auxAxis
VECTOR2I computeNearest(const VECTOR2I &aPoint, const VECTOR2I &aGrid, const VECTOR2I &aOffset) const
void retainAcceptedSnaps(const SNAP_RESULT &aResult)
Record which snaps the resolver accepted so they can be re-biased on the next resolve,...
std::optional< VECTOR2I > SnapToConstructionLines(const VECTOR2I &aPoint, const VECTOR2I &aNearestGrid, const VECTOR2D &aGrid, double aSnapRange) const
void SetSnapLineDirections(const std::vector< VECTOR2I > &aDirections)
VECTOR2I m_skipPoint
bool m_enableGrid
SNAP_RANGES computeSnapRanges(bool aClampToVisibleGrid) const
Compute the snap thresholds.
void emitAngleBranchCandidates(std::vector< SNAP_CANDIDATE > &aCandidates, const VECTOR2I &aOrigin, double aSnapScale) const
Emit the angle-restriction snap candidates (the two branches bracketing the cursor angle) into the cu...
virtual GRID_HELPER_GRIDS GetItemGrid(const EDA_ITEM *aItem) const
Get the coarsest grid that applies to an item.
void showConstructionGeometry(bool aShow)
SNAP_MANAGER m_snapManager
Manage the construction geometry, snap lines, reference points, etc.
virtual ~GRID_HELPER()
double m_angleStepDegrees
VECTOR2D m_manualVisibleGrid
void SetSnapLineOrigin(const VECTOR2I &aOrigin)
void ClearSkipPoint()
Clear the skip point by setting it to an unreachable position, thereby preventing matching.
bool m_manualGridSnapping
VECTOR2I m_manualOrigin
virtual GRID_HELPER_GRIDS GetSelectionGrid(const SELECTION &aSelection) const
Gets the coarsest grid that applies to a selecion of items.
TOOL_MANAGER * m_toolMgr
std::optional< VECTOR2I > GetSnappedPoint() const
void SetAuxAxes(bool aEnable, const VECTOR2I &aOrigin=VECTOR2I(0, 0))
VECTOR2D GetVisibleGrid() const
std::unique_ptr< KIGFX::ANCHOR_DEBUG > m_anchorDebug
#VIEW_ITEM for visualising anchor points, if enabled.
std::vector< VECTOR2I > m_stationarySelfPoints
virtual VECTOR2D GetGridSize(GRID_HELPER_GRIDS aGrid) const
Return the size of the specified grid.
SNAP_RESOLVER::TRACE_CALLBACK snapTraceCallback(const SNAP_SOURCE_CONTEXT &aContext) const
VECTOR2I GetGrid() const
static SNAP_REFERENCE_PREFERENCE classifyReference(const VECTOR2I &aPoint, const BOX2I &aBounds, bool aAnchorPoint)
Classify the point a drag was started from against the moving object's bounds.
bool m_enableSnapLine
bool m_enableSnap
VECTOR2I GetOrigin() const
bool canUseGrid() const
Check whether it is possible to use the grid – this depends both on local grid helper settings and gl...
void ClearSnapLine()
std::optional< SNAP_STABLE_ID > m_retainedAngleBranch
std::optional< ANCHOR > m_snapItem
SNAP_REFERENCE_PREFERENCE m_layoutReferencePreference
KIGFX::ANCHOR_DEBUG * enableAndGetAnchorDebug()
Enable the anchor debug if permitted and return it.
void SetSnapLineEnd(const std::optional< VECTOR2I > &aEnd)
KIGFX::SNAP_INDICATOR m_viewSnapPoint
virtual VECTOR2I Align(const VECTOR2I &aPoint, GRID_HELPER_GRIDS aGrid) const
void updateSnapPoint(const TYPED_POINT2I &aPoint)
KIGFX::ORIGIN_VIEWITEM m_viewAxis
std::optional< VECTOR2I > m_angleOrigin
std::vector< SNAP_STABLE_ID > m_stickySnapIds
void setLayoutReference(const VECTOR2I &aPoint, const std::optional< BOX2I > &aBounds, bool aAnchorPoint)
Record the classified drag reference and trace it.
void emitSelfAndGridCandidates(std::vector< SNAP_CANDIDATE > &aCandidates, const SNAP_SOURCE_CONTEXT &aContext, const VECTOR2I &aOrigin, const VECTOR2I &aNearestGrid, double aSnapScale, int aSnapRange, bool aUseGrid) const
Emit the point editor's unchanged self-geometry and the independent grid axes.
VECTOR2D m_manualGrid
void applySnapResultGuides(const SNAP_RESULT &aResult)
virtual VECTOR2I AlignGrid(const VECTOR2I &aPoint, GRID_HELPER_GRIDS aGrid) const
View item to draw debug items for anchors.
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:101
const VECTOR2D & GetGridOrigin() const
Container for all the knowledge about how graphical objects are drawn on any output surface/device.
const COLOR4D & GetLayerColor(int aLayer) const
Return the color used to draw a layer.
Hold a (potentially large) number of VIEW_ITEMs and renders them on a graphics device provided by the...
Definition view.h:63
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:300
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
Definition view.cpp:404
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:1835
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
Definition view.h:207
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:534
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
Definition view.h:225
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
Definition view.cpp:1805
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
Definition view.cpp:1756
EDA_ITEM * Front() const
Definition selection.h:176
const std::vector< VECTOR2I > & GetDirections() const
std::optional< int > GetActiveDirection() const
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.
const OPT_VECTOR2I & GetSnapLineOrigin() const
std::function< void(const std::string &)> TRACE_CALLBACK
Master controller class:
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
Definition vector2d.h:279
constexpr extended_type Dot(const VECTOR2< T > &aVector) const
Compute dot product of self with aVector.
Definition vector2d.h:542
GRID_HELPER_GRIDS
Definition grid_helper.h:55
bool m_EnableSnapAnchorsDebug
Enable snap anchors debug visualization.
int m_SnapHysteresis
Hysteresis in pixels used for snap activation and deactivation.
const wxChar *const traceSnap
Flag to enable snap/grid helper debug tracing.
@ GEOMETRY
Position or shape has changed.
Definition view_item.h:51
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:35
constexpr double SNAP_SCREEN_RADIUS
Screen-space radius (px) inside which a candidate is snappable.
SNAP_STABLE_ID MakeDerivedSnapId(SNAP_ID_KIND aKind, const SNAP_STABLE_ID &aSource, int aFeatureIndex=0, int aSolutionBranch=0)
World-space snap thresholds derived from the screen-space snap radius.
int range
Snap radius, optionally clamped to the visible grid.
int in
Distance at which a candidate is picked up.
double scale
SNAP_SCREEN_RADIUS in world units.
int out
Distance at which a held candidate is released.
double rankingHysteresis
Resolver ranking stickiness, as a fraction of the radius.
static SNAP_CANDIDATE Point(SNAP_STABLE_ID aId, SNAP_PRIORITY_TIER aPriority, SNAP_CANDIDATE_SUBTYPE aSubtype, const VECTOR2I &aPoint, double aResidual)
static SNAP_CANDIDATE Line(SNAP_STABLE_ID aId, SNAP_PRIORITY_TIER aPriority, SNAP_CANDIDATE_SUBTYPE aSubtype, const VECTOR2I &aOrigin, const VECTOR2D &aDirection, double aResidual)
static SNAP_CANDIDATE AxisY(SNAP_STABLE_ID aId, SNAP_PRIORITY_TIER aPriority, SNAP_CANDIDATE_SUBTYPE aSubtype, int aCoordinate, double aResidual)
static SNAP_CANDIDATE AxisX(SNAP_STABLE_ID aId, SNAP_PRIORITY_TIER aPriority, SNAP_CANDIDATE_SUBTYPE aSubtype, int aCoordinate, double aResidual)
SNAP_GUIDE_STYLE style
VECTOR2I end
VECTOR2I start
std::vector< SNAP_GUIDE > guides
std::vector< SNAP_STABLE_ID > accepted
std::optional< VECTOR2I > stationarySourceLeg
std::optional< BOX2I > movingBounds
std::optional< VECTOR2I > movingReferencePoint
std::optional< SNAP_STABLE_ID > movingItem
SNAP_EDITOR_PROFILE profile
VECTOR2I m_point
Definition point_types.h:73
int delta
wxLogTrace helper definitions.
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:683
VECTOR2< double > VECTOR2D
Definition vector2d.h:682