71        std::unique_lock<std::mutex> lock( 
m_mutex );
 
 
   81        std::unique_lock<std::mutex> lock( 
m_mutex );
 
   99        if( aAcceptImmediately )
 
 
  113        std::lock_guard<std::mutex> lock( 
m_mutex );
 
 
  129        std::unique_lock<std::mutex> lock( 
m_mutex );
 
 
 
  181    const std::chrono::milliseconds acceptanceTimeout(
 
  184    m_activationHelper = std::make_unique<ACTIVATION_HELPER<std::unique_ptr<PENDING_BATCH>>>(
 
  186            [
this]( std::unique_ptr<PENDING_BATCH>&& aAccepted )
 
  190                wxCHECK_MSG( aAccepted != 
nullptr, 
void(), 
"Null proposal accepted" );
 
 
  209    std::size_t hash = 
hash_val( aIsPersistent );
 
 
  220        std::unique_ptr<CONSTRUCTION_ITEM_BATCH> aBatch, 
bool aIsPersistent )
 
  222    if( aBatch->empty() )
 
  229    bool acceptImmediately = 
false;
 
  236            acceptImmediately = 
true;
 
  246            std::make_unique<PENDING_BATCH>( 
PENDING_BATCH{ std::move( *aBatch ), aIsPersistent } );
 
  250    m_activationHelper->ProposeActivation( std::move( pendingBatch ), hash, acceptImmediately );
 
 
  284    std::vector<CONSTRUCTION_ITEM_BATCH> persistentBatches, temporaryBatches;
 
  288        if( aAcceptedBatch->IsPersistent )
 
  295            bool anyNewItems = 
false;
 
  330            getInvolved( batch );
 
  331            temporaryBatches.push_back( batch );
 
  338    const auto addDrawables =
 
  339            [&]( 
const std::vector<CONSTRUCTION_ITEM_BATCH>& aBatches, 
bool aIsPersistent )
 
  353    addDrawables( persistentBatches, 
true );
 
  354    addDrawables( temporaryBatches, 
false );
 
 
  376        std::vector<CONSTRUCTION_ITEM_BATCH>& aToExtend )
 const 
  386        aToExtend.push_back( batch );
 
 
  408    if( aDir.
x == 0 && aDir.
y == 0 )
 
  422    if( dx < 0 || ( dx == 0 && dy < 0 ) )
 
 
  437    if( normalized.
x == 0 && normalized.
y == 0 )
 
  440    for( 
size_t i = 0; i < aDirections.size(); ++i )
 
  442        if( aDirections[i] == normalized )
 
  443            return static_cast<int>( i );
 
 
  452    std::vector<VECTOR2I> uniqueDirections;
 
  453    uniqueDirections.reserve( aDirections.size() );
 
  455    for( 
const VECTOR2I& direction : aDirections )
 
  459        if( normalized.
x == 0 && normalized.
y == 0 )
 
  462        if( std::find( uniqueDirections.begin(), uniqueDirections.end(), normalized )
 
  463                == uniqueDirections.end() )
 
  465            uniqueDirections.push_back( normalized );
 
 
  563                                                        std::optional<int> aDistToNearest,
 
  568    wxLogTrace( 
traceSnap, 
"GetNearestSnapLinePoint: cursor=(%d, %d), nearestGrid=(%d, %d), distToNearest=%s, snapRange=%d",
 
  569                aCursor.
x, aCursor.
y, aNearestGrid.
x, aNearestGrid.
y,
 
  570                aDistToNearest ? wxString::Format( 
"%d", *aDistToNearest ) : wxString( 
"none" ), aSnapRange );
 
  574        wxLogTrace( 
traceSnap, 
"  No snap line origin or no directions, returning nullopt" );
 
  578    const bool gridBetterThanNearest = !aDistToNearest || *aDistToNearest > aSnapRange;
 
  579    const bool gridActive = aGridSize.
x > 0 && aGridSize.
y > 0;
 
  581    wxLogTrace( 
traceSnap, 
"  snapLineOrigin=(%d, %d), directions count=%zu, gridBetterThanNearest=%d, gridActive=%d",
 
  584    if( !gridBetterThanNearest )
 
  586        wxLogTrace( 
traceSnap, 
"  Grid not better than nearest, returning nullopt" );
 
  590    const int       escapeRange = 2 * aSnapRange;
 
  593    wxLogTrace( 
traceSnap, 
"  escapeRange=%d, longRangeEscapeAngle=%.1f deg",
 
  594                escapeRange, longRangeEscapeAngle.
AsDegrees() );
 
  600    double                        bestPerpDistance = std::numeric_limits<double>::max();
 
  601    std::optional<VECTOR2I>       bestSnapPoint;
 
  609        if( dirLength == 0.0 )
 
  611            wxLogTrace( 
traceSnap, 
"    Direction %zu: zero length, skipping", ii );
 
  615        VECTOR2D dirUnit = dirVector / dirLength;
 
  617        double    distanceAlong = 
delta.Dot( dirUnit );
 
  618        VECTOR2D  projection = origin + dirUnit * distanceAlong;
 
  622        wxLogTrace( 
traceSnap, 
"    Direction %zu: dir=(%d, %d), perpDist=%.1f, distAlong=%.1f",
 
  623                    ii, direction.
x, direction.
y, perpDistance, distanceAlong );
 
  625        if( perpDistance > aSnapRange )
 
  627            wxLogTrace( 
traceSnap, 
"      perpDistance > snapRange, skipping" );
 
  631        bool escaped = 
false;
 
  633        if( perpDistance >= escapeRange )
 
  637            double    angleDiff = ( deltaAngle - directionAngle ).Normalize180().AsDegrees();
 
  639            wxLogTrace( 
traceSnap, 
"      In escape range: deltaAngle=%.1f, dirAngle=%.1f, angleDiff=%.1f",
 
  645                wxLogTrace( 
traceSnap, 
"      ESCAPED (angle diff too large)" );
 
  651            wxLogTrace( 
traceSnap, 
"      Not updating (escaped)" );
 
  661            if( direction.
x == 0 && direction.
y != 0 )
 
  664                snapPoint.
x = origin.
x;
 
  665                snapPoint.
y = aNearestGrid.
y;
 
  666                wxLogTrace( 
traceSnap, 
"      Vertical line: snapping to grid Y, snapPoint=(%.1f, %.1f)",
 
  667                            snapPoint.
x, snapPoint.
y );
 
  669            else if( direction.
y == 0 && direction.
x != 0 )
 
  672                snapPoint.
x = aNearestGrid.
x;
 
  673                snapPoint.
y = origin.
y;
 
  674                wxLogTrace( 
traceSnap, 
"      Horizontal line: snapping to grid X, snapPoint=(%.1f, %.1f)",
 
  675                            snapPoint.
x, snapPoint.
y );
 
  680                VECTOR2D gridOriginD( aGridOrigin );
 
  681                VECTOR2D relProjection = projection - gridOriginD;
 
  684                double   bestGridScore = std::numeric_limits<double>::max();
 
  685                VECTOR2D bestGridPoint = projection;
 
  687                for( 
int dx = -1; dx <= 1; ++dx )
 
  689                    for( 
int dy = -1; dy <= 1; ++dy )
 
  691                        double gridX = std::round( relProjection.
x / aGridSize.
x ) * aGridSize.
x + dx * aGridSize.
x;
 
  692                        double gridY = std::round( relProjection.
y / aGridSize.
y ) * aGridSize.
y + dy * aGridSize.
y;
 
  693                        VECTOR2D gridPt( gridX + gridOriginD.
x, gridY + gridOriginD.
y );
 
  696                        VECTOR2D gridDelta = gridPt - origin;
 
  697                        double   gridDistAlong = gridDelta.
Dot( dirUnit );
 
  698                        VECTOR2D gridProjection = origin + dirUnit * gridDistAlong;
 
  699                        double   gridPerpDist = ( gridPt - gridProjection ).EuclideanNorm();
 
  702                        double distFromCursor = ( gridPt - 
cursor ).EuclideanNorm();
 
  705                        double score = gridPerpDist + distFromCursor * 0.1;
 
  707                        if( score < bestGridScore )
 
  709                        bestGridScore = score;
 
  710                            bestGridPoint = gridPt;
 
  715                snapPoint = bestGridPoint;
 
  716                wxLogTrace( 
traceSnap, 
"      Diagonal line: snapping to grid intersection, snapPoint=(%.1f, %.1f)",
 
  717                            snapPoint.
x, snapPoint.
y );
 
  722            wxLogTrace( 
traceSnap, 
"      Grid not active, using projection" );
 
  725        if( perpDistance < bestPerpDistance )
 
  727            bestPerpDistance = perpDistance;
 
  729            wxLogTrace( 
traceSnap, 
"      NEW BEST: perpDist=%.1f, snapPoint=(%d, %d)",
 
  730                        bestPerpDistance, bestSnapPoint->x, bestSnapPoint->y );
 
  734            wxLogTrace( 
traceSnap, 
"      Not updating (perpDist=%.1f >= bestPerp=%.1f)",
 
  735                        perpDistance, bestPerpDistance );
 
  741        wxLogTrace( 
traceSnap, 
"  RETURNING bestSnapPoint=(%d, %d)", bestSnapPoint->x, bestSnapPoint->y );
 
  742        return *bestSnapPoint;
 
  745    wxLogTrace( 
traceSnap, 
"  RETURNING nullopt (no valid snap found)" );
 
 
  782    std::vector<KIGFX::CONSTRUCTION_GEOM::SNAP_GUIDE> guides;
 
  787    if( origin && !directions.empty() )
 
  789        const std::optional<int> activeDirection = 
m_snapLineManager.GetActiveDirection();
 
  790        const int                 guideLength = 500000;
 
  792        for( 
size_t ii = 0; ii < directions.size(); ++ii )
 
  794            const VECTOR2I& direction = directions[ii];
 
  796            if( direction.
x == 0 && direction.
y == 0 )
 
  799            VECTOR2I scaled = direction * guideLength;
 
  802            guide.
Segment = 
SEG( *origin - scaled, *origin + scaled );
 
  804            if( activeDirection && *activeDirection == 
static_cast<int>( ii ) )
 
  815            guides.push_back( guide );
 
 
  831std::vector<CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM_BATCH>
 
  834    std::vector<CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM_BATCH> batches;
 
  839        snapLineOrigin.has_value() )
 
  851        const std::optional<int>     activeDirection = 
m_snapLineManager.GetActiveDirection();
 
  853        for( 
size_t ii = 0; ii < directions.size(); ++ii )
 
  855            const VECTOR2I& direction = directions[ii];
 
  857            VECTOR2I scaledDirection = direction * 100000;
 
  860            entry.
Drawable = 
LINE{ *snapLineOrigin, *snapLineOrigin + scaledDirection };
 
  861            entry.
LineWidth = ( activeDirection && *activeDirection == 
static_cast<int>( ii ) ) ? 2 : 1;
 
  867            batches.push_back( std::move( batch ) );
 
 
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
 
void onTimerExpiry(wxTimerEvent &aEvent)
Timer expiry callback in the UI thread.
 
void acceptPendingProposal()
 
ACTIVATION_HELPER(std::chrono::milliseconds aTimeout, ACTIVATION_CALLBACK aCallback)
 
std::optional< std::size_t > m_lastAcceptedProposalTag
The last proposal that was accepted.
 
ACTIVATION_CALLBACK m_callback
Callback to call when the proposal is accepted.
 
std::chrono::milliseconds m_timeout
Activation timeout in milliseconds.
 
void ProposeActivation(T &&aProposal, std::size_t aProposalTag, bool aAcceptImmediately)
 
std::optional< std::size_t > m_pendingProposalTag
The last proposal tag that was made.
 
T m_lastProposal
The most recently-proposed item.
 
std::function< void(T &&)> ACTIVATION_CALLBACK
 
static const ADVANCED_CFG & GetCfg()
Get the singleton instance's config, which is shared by all consumers.
 
A color representation with 4 components: red, green, blue, alpha.
 
void GetConstructionItems(std::vector< CONSTRUCTION_ITEM_BATCH > &aToExtend) const
Get the list of additional geometry items that should be considered.
 
void ProposeConstructionItems(std::unique_ptr< CONSTRUCTION_ITEM_BATCH > aBatch, bool aIsPersistent)
Add a batch of construction items to the helper.
 
CONSTRUCTION_VIEW_HANDLER & m_viewHandler
 
bool HasActiveConstruction() const
 
CONSTRUCTION_MANAGER(CONSTRUCTION_VIEW_HANDLER &aViewHandler)
 
void CancelProposal()
Cancel outstanding proposals for new geometry.
 
std::deque< CONSTRUCTION_ITEM_BATCH > m_temporaryConstructionBatches
Temporary construction items are added and removed as needed.
 
std::vector< CONSTRUCTION_ITEM > CONSTRUCTION_ITEM_BATCH
 
std::optional< CONSTRUCTION_ITEM_BATCH > m_persistentConstructionBatch
Within one "operation", there is one set of construction items that are "persistent",...
 
std::unique_ptr< ACTIVATION_HELPER< std::unique_ptr< PENDING_BATCH > > > m_activationHelper
 
unsigned getMaxTemporaryBatches() const
How many batches of temporary construction items can be active at once.
 
std::mutex m_batchesMutex
Protects the persistent and temporary construction batches.
 
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...
 
void acceptConstructionItems(std::unique_ptr< PENDING_BATCH > aAcceptedBatchHash)
 
std::set< EDA_ITEM * > m_involvedItems
Set of all items for which construction geometry has been added.
 
Interface wrapper for the construction geometry preview with a callback to signal the view owner that...
 
CONSTRUCTION_VIEW_HANDLER(KIGFX::CONSTRUCTION_GEOM &aHelper)
 
KIGFX::CONSTRUCTION_GEOM & GetViewItem()
 
A base class for most all the KiCad significant classes used in schematics and boards.
 
A color representation with 4 components: red, green, blue, alpha.
 
Shows construction geometry for things like line extensions, arc centers, etc.
 
void AddDrawable(const DRAWABLE &aItem, bool aIsPersistent, int aLineWidth=1)
 
void SetSnapGuides(std::vector< SNAP_GUIDE > aGuides)
 
OPT_VECTOR2I GetNearestSnapLinePoint(const VECTOR2I &aCursor, const VECTOR2I &aNearestGrid, std::optional< int > aDistToNearest, int snapRange, const VECTOR2D &aGridSize=VECTOR2D(0, 0), const VECTOR2I &aGridOrigin=VECTOR2I(0, 0)) const
If the snap line is active, return the best snap point that is closest to the cursor.
 
OPT_VECTOR2I m_snapLineEnd
 
void SetDirections(const std::vector< VECTOR2I > &aDirections)
 
void SetSnappedAnchor(const VECTOR2I &aAnchorPos)
Inform this manager that an anchor snap has been made.
 
CONSTRUCTION_VIEW_HANDLER & m_viewHandler
 
void ClearSnapLine()
Clear the snap line origin and end points.
 
std::vector< VECTOR2I > m_directions
 
SNAP_MANAGER * m_snapManager
 
SNAP_LINE_MANAGER(CONSTRUCTION_VIEW_HANDLER &aViewHandler)
 
void SetSnapLineOrigin(const VECTOR2I &aOrigin)
The snap point is a special point that is located at the last point the cursor snapped to.
 
std::optional< int > m_activeDirection
 
void SetSnapLineEnd(const OPT_VECTOR2I &aSnapPoint)
Set the end point of the snap line.
 
OPT_VECTOR2I m_snapLineOrigin
 
A SNAP_MANAGER glues together the snap line manager and construction manager., along with some other ...
 
void SetSnapGuideColors(const KIGFX::COLOR4D &aBase, const KIGFX::COLOR4D &aHighlight)
 
KIGFX::COLOR4D m_snapGuideColor
 
KIGFX::COLOR4D m_snapGuideHighlightColor
 
GFX_UPDATE_CALLBACK m_updateCallback
 
CONSTRUCTION_MANAGER m_constructionManager
 
std::vector< CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM_BATCH > GetConstructionItems() const
Get a list of all the active construction geometry, computed from the combined state of the snap line...
 
void updateView() override
 
SNAP_LINE_MANAGER m_snapLineManager
 
SNAP_MANAGER(KIGFX::CONSTRUCTION_GEOM &aHelper)
 
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.
 
static std::size_t HashConstructionBatchSources(const CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM_BATCH &aBatch, bool aIsPersistent)
Construct a hash based on the sources of the items in the batch.
 
static VECTOR2I normalizeDirection(const VECTOR2I &aDir)
 
static std::optional< int > findDirectionIndex(const std::vector< VECTOR2I > &aDirections, const VECTOR2I &aDelta)
 
const wxChar *const traceSnap
Flag to enable snap/grid helper debug tracing.
 
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
 
static constexpr std::size_t hash_val(const Types &... args)
 
The Cairo implementation of the graphics abstraction layer.
 
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
 
std::optional< VECTOR2I > OPT_VECTOR2I
 
KIGFX::CONSTRUCTION_GEOM::DRAWABLE Drawable
 
Items to be used for the construction of "virtual" anchors, for example, when snapping to a point inv...
 
std::vector< DRAWABLE_ENTRY > Constructions
 
CONSTRUCTION_ITEM_BATCH Batch
 
wxLogTrace helper definitions.
 
VECTOR2< int32_t > VECTOR2I
 
VECTOR2< double > VECTOR2D