79 [view,
this](
bool aAnythingShown )
83 if( currentlyVisible && aAnythingShown )
94 holder->RefreshCanvas();
146 m_snapManager.GetSnapLineManager().SetDirections( aDirections );
152 m_snapManager.GetSnapLineManager().SetSnapLineOrigin( aOrigin );
168 std::vector<SEG> dimensionBrackets;
175 dimensionBrackets.emplace_back( guide.
start, guide.
end );
176 wxLogTrace( wxT(
"KICAD_SNAP_RESOLVER" ),
"bracket axis=%c start=(%d,%d) end=(%d,%d)",
186 m_snapManager.SetDimensionBrackets( std::move( dimensionBrackets ) );
205 const auto nearestFeature = [](
int aCoordinate,
const std::array<int, 3>& aFeatures )
221 nearestFeature( aPoint.
y, yFeatures ) };
232 const char* referenceKind =
"none";
235 referenceKind =
"bounds";
237 referenceKind =
"anchor-point";
239 wxLogTrace( wxT(
"KICAD_SNAP_RESOLVER" ),
"drag reference kind=%s x-feature=%d y-feature=%d", referenceKind,
245 const VECTOR2D& aGrid,
double aSnapRange )
const
250 wxLogTrace(
traceSnap,
"SnapToConstructionLines: aPoint=(%d, %d), nearestGrid=(%d, %d), snapRange=%.1f", aPoint.
x,
251 aPoint.
y, aNearestGrid.
x, aNearestGrid.
y, aSnapRange );
255 wxLogTrace(
traceSnap,
" No snap origin or no directions, returning nullopt" );
259 const VECTOR2I& origin = *snapOrigin;
261 wxLogTrace(
traceSnap,
" snapOrigin=(%d, %d), directions count=%zu",
264 const std::vector<VECTOR2I>& directions = snapLineManager.
GetDirections();
267 if( activeDirection )
268 wxLogTrace(
traceSnap,
" activeDirection=%d", *activeDirection );
274 std::optional<VECTOR2I> bestPoint;
275 double bestPerp = std::numeric_limits<double>::max();
276 double bestDistance = std::numeric_limits<double>::max();
278 for(
size_t ii = 0; ii < directions.size(); ++ii )
280 const VECTOR2I& dir = directions[ii];
284 if( dirLength == 0.0 )
286 wxLogTrace(
traceSnap,
" Direction %zu: zero length, skipping", ii );
290 VECTOR2D dirUnit = dirVector / dirLength;
292 double distanceAlong =
delta.Dot( dirUnit );
293 VECTOR2D projection = originVec + dirUnit * distanceAlong;
297 double snapThreshold = aSnapRange;
299 if( activeDirection && *activeDirection ==
static_cast<int>( ii ) )
301 snapThreshold *= 1.5;
302 wxLogTrace(
traceSnap,
" Direction %zu: ACTIVE, increased snapThreshold=%.1f", ii, snapThreshold );
305 wxLogTrace(
traceSnap,
" Direction %zu: dir=(%d, %d), perpDist=%.1f, threshold=%.1f",
306 ii, dir.
x, dir.
y, perpDistance, snapThreshold );
308 if( perpDistance > snapThreshold )
310 wxLogTrace(
traceSnap,
" perpDistance > threshold, skipping" );
318 if( dir.
x == 0 && dir.
y != 0 )
321 candidate.
x = origin.
x;
322 candidate.
y = aNearestGrid.
y;
323 wxLogTrace(
traceSnap,
" Vertical snap: candidate=(%d, %d)", (
int) candidate.
x,
326 else if( dir.
y == 0 && dir.
x != 0 )
329 candidate.
x = aNearestGrid.
x;
330 candidate.
y = origin.
y;
331 wxLogTrace(
traceSnap,
" Horizontal snap: candidate=(%d, %d)", (
int) candidate.
x,
344 VECTOR2D relProjection = projection - gridOrigin;
347 std::vector<VECTOR2D> gridPoints;
348 for(
int dx = -1; dx <= 1; ++dx )
350 for(
int dy = -1; dy <= 1; ++dy )
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 ) );
359 double bestGridDist = std::numeric_limits<double>::max();
362 for(
const VECTOR2D& gridPt : gridPoints )
365 VECTOR2D gridDelta = gridPt - originVec;
366 double gridDistAlong = gridDelta.
Dot( dirUnit );
367 VECTOR2D gridProjection = originVec + dirUnit * gridDistAlong;
368 double gridPerpDist = ( gridPt - gridProjection ).EuclideanNorm();
371 double distFromCursor = ( gridPt - cursorVec ).EuclideanNorm();
374 double score = gridPerpDist + distFromCursor * 0.1;
376 if( score < bestGridDist )
378 bestGridDist = score;
383 candidate = bestGridPt;
384 wxLogTrace(
traceSnap,
" Diagonal snap: candidate=(%.1f, %.1f), perpDist=%.1f",
385 candidate.
x, candidate.
y, bestGridDist );
390 wxLogTrace(
traceSnap,
" Grid disabled, using projection candidate=(%.1f, %.1f)",
391 candidate.
x, candidate.
y );
398 wxLogTrace(
traceSnap,
" candidateInt matches m_skipPoint, skipping" );
402 VECTOR2D candidateDelta( candidateInt.
x - aPoint.
x, candidateInt.
y - aPoint.
y );
403 double candidateDistance = candidateDelta.EuclideanNorm();
405 wxLogTrace(
traceSnap,
" candidateInt=(%d, %d), candidateDist=%.1f",
406 candidateInt.
x, candidateInt.
y, candidateDistance );
408 if( perpDistance < bestPerp
409 || (
std::abs( perpDistance - bestPerp ) < 1e-9 && candidateDistance < bestDistance ) )
411 wxLogTrace(
traceSnap,
" NEW BEST: perpDist=%.1f, candDist=%.1f", perpDistance, candidateDistance );
412 bestPerp = perpDistance;
413 bestDistance = candidateDistance;
414 bestPoint = candidateInt;
420 wxLogTrace(
traceSnap,
" RETURNING bestPoint=(%d, %d)", bestPoint->x, bestPoint->y );
424 wxLogTrace(
traceSnap,
" RETURNING nullopt (no valid snap found)" );
533 KiROUND( (
double) ( aPoint.
y - aOffset.
y ) / aGrid.
y ) * aGrid.
y + aOffset.
y );
591 const int hysteresisWorld =
KiROUND( view->
ToWorld( hysteresisPixels ) );
593 ranges.
in = std::max( 0, ranges.
range - hysteresisWorld );
594 ranges.
out = ranges.
range + hysteresisWorld;
602 double aSnapScale )
const
609 double rawAngle = std::atan2(
delta.y,
delta.x );
610 int lowerBranch =
static_cast<int>( std::floor( rawAngle / step ) );
612 for(
int branch : { lowerBranch, lowerBranch + 1 } )
614 double angle = branch * step;
615 VECTOR2D direction( std::cos( angle ), std::sin( angle ) );
626 static const wxString traceCategory = wxT(
"KICAD_SNAP_RESOLVER" );
627 const auto callback = [](
const std::string& aMessage )
629 wxLogTrace( traceCategory,
"%s", aMessage.c_str() );
632 if( !wxLog::IsAllowedTraceMask( traceCategory ) )
637 wxLogTrace( traceCategory,
"context raw=(%d,%d) reference=none bounds=none", aContext.
sourcePoint.
x,
647 wxLogTrace( traceCategory,
"context raw=(%d,%d) reference=(%d,%d) bounds=(%d,%d,%d,%d) projected=(%d,%d,%d,%d)",
661 const VECTOR2I& aNearestGrid,
double aSnapScale,
int aSnapRange,
662 bool aUseGrid )
const
694 std::abs( aNearestGrid.
x - aOrigin.
x ) / aSnapScale ) );
697 std::abs( aNearestGrid.
y - aOrigin.
y ) / aSnapScale ) );
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
constexpr Vec Centre() const
constexpr coord_type GetLeft() const
constexpr coord_type GetRight() const
constexpr coord_type GetTop() const
constexpr void Offset(coord_type dx, coord_type dy)
constexpr coord_type GetBottom() const
A base class for most all the KiCad significant classes used in schematics and boards.
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)
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.
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
virtual GRID_HELPER_GRIDS GetSelectionGrid(const SELECTION &aSelection) const
Gets the coarsest grid that applies to a selecion of items.
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
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.
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...
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.
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.
const VECTOR2D & GetGridOrigin() const
bool GetGridSnapping() 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...
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
virtual void Remove(VIEW_ITEM *aItem)
Remove a VIEW_ITEM from the view.
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...
GAL * GetGAL() const
Return the GAL this view is using to draw graphical primitives.
VECTOR2D ToWorld(const VECTOR2D &aCoord, bool aAbsolute=true) const
Converts a screen space point/vector to a point/vector in world space coordinates.
PAINTER * GetPainter() const
Return the painter object used by the view for drawing #VIEW_ITEMS.
bool IsVisible(const VIEW_ITEM *aItem) const
Return information if the item is visible (or not).
void SetVisible(VIEW_ITEM *aItem, bool aIsVisible=true)
Set the item visibility.
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
T EuclideanNorm() const
Compute the Euclidean norm of the vector, which is defined as sqrt(x ** 2 + y ** 2).
constexpr extended_type Dot(const VECTOR2< T > &aVector) const
Compute dot product of self with aVector.
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.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
std::optional< VECTOR2I > OPT_VECTOR2I
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)
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
wxLogTrace helper definitions.
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D