KiCad PCB EDA Suite
Loading...
Searching...
No Matches
construction_manager.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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <algorithm>
27#include <chrono>
28#include <cmath>
29#include <limits>
30#include <numeric>
31#include <utility>
32
33#include <wx/timer.h>
34#include <wx/debug.h>
35
36#include <advanced_config.h>
37#include <math/util.h>
38#include <hash.h>
39
40
52template <typename T>
54{
55public:
56 using ACTIVATION_CALLBACK = std::function<void( T&& )>;
57
58 ACTIVATION_HELPER( std::chrono::milliseconds aTimeout, ACTIVATION_CALLBACK aCallback ) :
59 m_timeout( aTimeout ),
60 m_callback( std::move( aCallback ) )
61 {
62 m_timer.Bind( wxEVT_TIMER, &ACTIVATION_HELPER::onTimerExpiry, this );
63 }
64
66 {
67 // Hold the lock while shutting down to prevent a propoal being accepted
68 // while state is being destroyed.
69 std::unique_lock<std::mutex> lock( m_mutex );
70 m_timer.Stop();
71 m_timer.Unbind( wxEVT_TIMER, &ACTIVATION_HELPER::onTimerExpiry, this );
72
73 // Should be redundant to inhibiting timer callbacks, but make it explicit.
75 }
76
77 void ProposeActivation( T&& aProposal, std::size_t aProposalTag, bool aAcceptImmediately )
78 {
79 std::unique_lock<std::mutex> lock( m_mutex );
80
81 if( m_lastAcceptedProposalTag.has_value() && aProposalTag == *m_lastAcceptedProposalTag )
82 {
83 // This proposal was accepted last time
84 // (could be made optional if we want to allow re-accepting the same proposal)
85 return;
86 }
87
88 if( m_pendingProposalTag.has_value() && aProposalTag == *m_pendingProposalTag )
89 {
90 // This proposal is already pending
91 return;
92 }
93
94 m_pendingProposalTag = aProposalTag;
95 m_lastProposal = std::move( aProposal );
96
97 if( aAcceptImmediately )
98 {
99 // Synchonously accept the proposal
100 lock.unlock();
102 }
103 else
104 {
105 m_timer.Start( m_timeout.count(), wxTIMER_ONE_SHOT );
106 }
107 }
108
110 {
111 std::lock_guard<std::mutex> lock( m_mutex );
112 m_pendingProposalTag.reset();
113 m_timer.Stop();
114 }
115
116private:
120 void onTimerExpiry( wxTimerEvent& aEvent )
121 {
123 }
124
126 {
127 std::unique_lock<std::mutex> lock( m_mutex );
128
130 {
132 m_pendingProposalTag.reset();
133
134 // Move out from the locked variable
135 T proposalToAccept = std::move( m_lastProposal );
136 lock.unlock();
137
138 // Call the callback (outside the lock)
139 // This is all in the UI thread now, so it won't be concurrent
140 m_callback( std::move( proposalToAccept ) );
141 }
142 }
143
144 mutable std::mutex m_mutex;
145
147 std::chrono::milliseconds m_timeout;
148
150 std::optional<std::size_t> m_pendingProposalTag;
151
153 std::optional<std::size_t> m_lastAcceptedProposalTag;
154
157
160
161 wxTimer m_timer;
162};
163
164
170
171
173 m_viewHandler( aHelper ),
178{
179 const std::chrono::milliseconds acceptanceTimeout(
180 ADVANCED_CFG::GetCfg().m_ExtensionSnapTimeoutMs );
181
182 m_activationHelper = std::make_unique<ACTIVATION_HELPER<std::unique_ptr<PENDING_BATCH>>>(
183 acceptanceTimeout,
184 [this]( std::unique_ptr<PENDING_BATCH>&& aAccepted )
185 {
186 // This shouldn't be possible (probably indicates a race in destruction of something)
187 // but at least avoid blowing up acceptConstructionItems.
188 wxCHECK_MSG( aAccepted != nullptr, void(), "Null proposal accepted" );
189
190 acceptConstructionItems( std::move( aAccepted ) );
191 } );
192}
193
194
198
199
203static std::size_t
205 bool aIsPersistent )
206{
207 std::size_t hash = hash_val( aIsPersistent );
208
209 for( const CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM& item : aBatch )
210 {
211 hash_combine( hash, item.Source, item.Item );
212 }
213 return hash;
214}
215
216
218 std::unique_ptr<CONSTRUCTION_ITEM_BATCH> aBatch, bool aIsPersistent )
219{
220 if( aBatch->empty() )
221 {
222 // There's no point in proposing an empty batch
223 // It would just clear existing construction items for nothing new
224 return;
225 }
226
227 bool acceptImmediately = false;
228
229 {
230 std::lock_guard<std::mutex> lock( m_batchesMutex );
231
232 if( aIsPersistent )
233 {
234 acceptImmediately = true;
235 }
236 else
237 {
238 // If the batch is temporary, we can accept it immediately if there's room
239 acceptImmediately = m_temporaryConstructionBatches.size() < getMaxTemporaryBatches();
240 }
241 }
242
243 auto pendingBatch =
244 std::make_unique<PENDING_BATCH>( PENDING_BATCH{ std::move( *aBatch ), aIsPersistent } );
245 const std::size_t hash = HashConstructionBatchSources( pendingBatch->Batch, aIsPersistent );
246
247 // Immediate or not, propose the batch via the activation helper as this handles duplicates
248 m_activationHelper->ProposeActivation( std::move( pendingBatch ), hash, acceptImmediately );
249}
250
251
253{
254 m_activationHelper->CancelProposal();
255}
256
257
259{
260 // We only keep up to one previous temporary batch and the current one
261 // we could make this a setting if we want to keep more, but it gets cluttered
262 return 2;
263}
264
265
266void CONSTRUCTION_MANAGER::acceptConstructionItems( std::unique_ptr<PENDING_BATCH> aAcceptedBatch )
267{
268 const auto getInvolved = [&]( const CONSTRUCTION_ITEM_BATCH& aBatchToAdd )
269 {
270 for( const CONSTRUCTION_ITEM& item : aBatchToAdd )
271 {
272 // Only show the item if it's not already involved
273 // (avoid double-drawing the same item)
274 if( m_involvedItems.count( item.Item ) == 0 )
275 {
276 m_involvedItems.insert( item.Item );
277 }
278 }
279 };
280
281 // Copies for use outside the lock
282 std::vector<CONSTRUCTION_ITEM_BATCH> persistentBatches, temporaryBatches;
283 {
284 std::lock_guard<std::mutex> lock( m_batchesMutex );
285
286 if( aAcceptedBatch->IsPersistent )
287 {
288 // We only keep one previous persistent batch for the moment
289 m_persistentConstructionBatch = std::move( aAcceptedBatch->Batch );
290 }
291 else
292 {
293 bool anyNewItems = false;
294 for( CONSTRUCTION_ITEM& item : aAcceptedBatch->Batch )
295 {
296 if( m_involvedItems.count( item.Item ) == 0 )
297 {
298 anyNewItems = true;
299 break;
300 }
301 }
302
303 // If there are no new items involved, don't bother adding the batch
304 if( !anyNewItems )
305 {
306 return;
307 }
308
310 {
312 }
313
314 m_temporaryConstructionBatches.emplace_back( std::move( aAcceptedBatch->Batch ) );
315 }
316
317 m_involvedItems.clear();
318
319 // Copy the batches for use outside the lock
321 {
322 getInvolved( *m_persistentConstructionBatch );
323 persistentBatches.push_back( *m_persistentConstructionBatch );
324 }
325
327 {
328 getInvolved( batch );
329 temporaryBatches.push_back( batch );
330 }
331 }
332
333 KIGFX::CONSTRUCTION_GEOM& geom = m_viewHandler.GetViewItem();
334 geom.ClearDrawables();
335
336 const auto addDrawables =
337 [&]( const std::vector<CONSTRUCTION_ITEM_BATCH>& aBatches, bool aIsPersistent )
338 {
339 for( const CONSTRUCTION_ITEM_BATCH& batch : aBatches )
340 {
341 for( const CONSTRUCTION_ITEM& item : batch )
342 {
343 for( const CONSTRUCTION_ITEM::DRAWABLE_ENTRY& drawable : item.Constructions )
344 {
345 geom.AddDrawable( drawable.Drawable, aIsPersistent, drawable.LineWidth );
346 }
347 }
348 }
349 };
350
351 addDrawables( persistentBatches, true );
352 addDrawables( temporaryBatches, false );
353
354 m_viewHandler.updateView();
355}
356
357
358bool CONSTRUCTION_MANAGER::InvolvesAllGivenRealItems( const std::vector<EDA_ITEM*>& aItems ) const
359{
360 for( EDA_ITEM* item : aItems )
361 {
362 // Null items (i.e. construction items) are always considered involved
363 if( item && m_involvedItems.count( item ) == 0 )
364 {
365 return false;
366 }
367 }
368
369 return true;
370}
371
372
374 std::vector<CONSTRUCTION_ITEM_BATCH>& aToExtend ) const
375{
376 std::lock_guard<std::mutex> lock( m_batchesMutex );
378 {
379 aToExtend.push_back( *m_persistentConstructionBatch );
380 }
381
383 {
384 aToExtend.push_back( batch );
385 }
386}
387
388
390{
391 std::lock_guard<std::mutex> lock( m_batchesMutex );
393}
394
395
397 m_viewHandler( aViewHandler ), m_snapManager( static_cast<SNAP_MANAGER*>( &aViewHandler ) )
398{
399 wxASSERT( m_snapManager );
400 SetDirections( { VECTOR2I( 1, 0 ), VECTOR2I( 0, 1 ) } );
401}
402
403
405{
406 if( aDir.x == 0 && aDir.y == 0 )
407 return VECTOR2I( 0, 0 );
408
409 int dx = aDir.x;
410 int dy = aDir.y;
411
412 int gcd = std::gcd( std::abs( dx ), std::abs( dy ) );
413
414 if( gcd > 0 )
415 {
416 dx /= gcd;
417 dy /= gcd;
418 }
419
420 if( dx < 0 || ( dx == 0 && dy < 0 ) )
421 {
422 dx = -dx;
423 dy = -dy;
424 }
425
426 return VECTOR2I( dx, dy );
427}
428
429
430static std::optional<int> findDirectionIndex( const std::vector<VECTOR2I>& aDirections,
431 const VECTOR2I& aDelta )
432{
433 VECTOR2I normalized = normalizeDirection( aDelta );
434
435 if( normalized.x == 0 && normalized.y == 0 )
436 return std::nullopt;
437
438 for( size_t i = 0; i < aDirections.size(); ++i )
439 {
440 if( aDirections[i] == normalized )
441 return static_cast<int>( i );
442 }
443
444 return std::nullopt;
445}
446
447
448void SNAP_LINE_MANAGER::SetDirections( const std::vector<VECTOR2I>& aDirections )
449{
450 std::vector<VECTOR2I> uniqueDirections;
451 uniqueDirections.reserve( aDirections.size() );
452
453 for( const VECTOR2I& direction : aDirections )
454 {
455 VECTOR2I normalized = normalizeDirection( direction );
456
457 if( normalized.x == 0 && normalized.y == 0 )
458 continue;
459
460 if( std::find( uniqueDirections.begin(), uniqueDirections.end(), normalized )
461 == uniqueDirections.end() )
462 {
463 uniqueDirections.push_back( normalized );
464 }
465 }
466
467 if( uniqueDirections != m_directions )
468 {
469 m_directions = std::move( uniqueDirections );
470 m_activeDirection.reset();
471
473 {
475 m_snapLineEnd.reset();
476 }
477
478 if( m_directions.empty() )
479 {
481 return;
482 }
483
485 }
486}
487
488
490{
491 if( m_snapLineOrigin && *m_snapLineOrigin == aOrigin && !m_snapLineEnd )
492 {
494 return;
495 }
496
497 m_snapLineOrigin = aOrigin;
498 m_snapLineEnd.reset();
499 m_activeDirection.reset();
500 m_viewHandler.GetViewItem().ClearSnapLine();
502}
503
504
506{
507 if( m_snapLineOrigin && aSnapEnd != m_snapLineEnd )
508 {
509 m_snapLineEnd = aSnapEnd;
510
511 if( m_snapLineEnd )
513 else
514 m_activeDirection.reset();
515
516 if( m_snapLineEnd )
517 m_viewHandler.GetViewItem().SetSnapLine( SEG{ *m_snapLineOrigin, *m_snapLineEnd } );
518 else
519 m_viewHandler.GetViewItem().ClearSnapLine();
520
522 }
523}
524
525
527{
528 m_snapLineOrigin.reset();
529 m_snapLineEnd.reset();
530 m_activeDirection.reset();
531 m_viewHandler.GetViewItem().ClearSnapLine();
533}
534
535
537{
538 if( m_snapLineOrigin.has_value() )
539 {
540 if( findDirectionIndex( m_directions, aAnchorPos - *m_snapLineOrigin ) )
541 {
542 SetSnapLineEnd( aAnchorPos );
543 }
544 else
545 {
546 // Snapped to something that is not the snap line origin, so
547 // this anchor is now the new snap line origin
548 SetSnapLineOrigin( aAnchorPos );
549 }
550 }
551 else
552 {
553 // If there's no snap line, start one
554 SetSnapLineOrigin( aAnchorPos );
555 }
556}
557
558
560 const VECTOR2I& aNearestGrid,
561 std::optional<int> aDistToNearest,
562 int aSnapRange ) const
563{
564 wxUnusedVar( aNearestGrid );
565
566 if( !m_snapLineOrigin || m_directions.empty() )
567 return std::nullopt;
568
569 const bool gridBetterThanNearest = !aDistToNearest || *aDistToNearest > aSnapRange;
570
571 if( !gridBetterThanNearest )
572 return std::nullopt;
573
574 const int escapeRange = 2 * aSnapRange;
575 const EDA_ANGLE longRangeEscapeAngle( 4, DEGREES_T );
576
577 const VECTOR2D origin( *m_snapLineOrigin );
578 const VECTOR2D cursor( aCursor );
579 const VECTOR2D delta = cursor - origin;
580
581 double bestPerpDistance = std::numeric_limits<double>::max();
582 std::optional<VECTOR2I> bestSnapPoint;
583
584 for( const VECTOR2I& direction : m_directions )
585 {
586 VECTOR2D dirVector( direction );
587 double dirLength = dirVector.EuclideanNorm();
588
589 if( dirLength == 0.0 )
590 continue;
591
592 VECTOR2D dirUnit = dirVector / dirLength;
593
594 double distanceAlong = delta.Dot( dirUnit );
595 VECTOR2D projection = origin + dirUnit * distanceAlong;
596 VECTOR2D offset = delta - dirUnit * distanceAlong;
597 double perpDistance = offset.EuclideanNorm();
598
599 if( perpDistance > aSnapRange )
600 continue;
601
602 bool escaped = false;
603
604 if( perpDistance >= escapeRange )
605 {
606 EDA_ANGLE deltaAngle( delta );
607 EDA_ANGLE directionAngle( dirVector );
608 double angleDiff = ( deltaAngle - directionAngle ).Normalize180().AsDegrees();
609
610 if( std::abs( angleDiff ) > longRangeEscapeAngle.AsDegrees() )
611 escaped = true;
612 }
613
614 if( !escaped && perpDistance < bestPerpDistance )
615 {
616 bestPerpDistance = perpDistance;
617 bestSnapPoint = VECTOR2I( KiROUND( projection.x ), KiROUND( projection.y ) );
618 }
619 }
620
621 if( bestSnapPoint )
622 return *bestSnapPoint;
623
624 return std::nullopt;
625}
626
627
634
635
637{
638 if( m_updateCallback )
639 {
640 bool showAnything = m_constructionManager.HasActiveConstruction()
641 || m_snapLineManager.HasCompleteSnapLine()
642 || ( m_snapLineManager.GetSnapLineOrigin()
643 && !m_snapLineManager.GetDirections().empty() );
644
645 m_updateCallback( showAnything );
646 }
647}
648
649
651{
652 m_snapGuideColor = aBase;
653 m_snapGuideHighlightColor = aHighlight;
655}
656
657
659{
660 std::vector<KIGFX::CONSTRUCTION_GEOM::SNAP_GUIDE> guides;
661
662 const OPT_VECTOR2I& origin = m_snapLineManager.GetSnapLineOrigin();
663 const std::vector<VECTOR2I>& directions = m_snapLineManager.GetDirections();
664
665 if( origin && !directions.empty() )
666 {
667 const std::optional<int> activeDirection = m_snapLineManager.GetActiveDirection();
668 const int guideLength = 500000;
669
670 for( size_t ii = 0; ii < directions.size(); ++ii )
671 {
672 const VECTOR2I& direction = directions[ii];
673
674 if( direction.x == 0 && direction.y == 0 )
675 continue;
676
677 VECTOR2I scaled = direction * guideLength;
678
680 guide.Segment = SEG( *origin - scaled, *origin + scaled );
681
682 if( activeDirection && *activeDirection == static_cast<int>( ii ) )
683 {
684 guide.LineWidth = 5;
686 }
687 else
688 {
689 guide.LineWidth = 1;
690 guide.Color = m_snapGuideColor;
691 }
692
693 guides.push_back( guide );
694 }
695 }
696
697 GetViewItem().SetSnapGuides( std::move( guides ) );
698 updateView();
699}
700
701
703{
704 if( m_snapManager )
705 m_snapManager->UpdateSnapGuides();
706}
707
708
709std::vector<CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM_BATCH>
711{
712 std::vector<CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM_BATCH> batches;
713
714 m_constructionManager.GetConstructionItems( batches );
715
716 if( const OPT_VECTOR2I& snapLineOrigin = m_snapLineManager.GetSnapLineOrigin();
717 snapLineOrigin.has_value() )
718 {
720
722 batch.emplace_back( CONSTRUCTION_MANAGER::CONSTRUCTION_ITEM{
724 nullptr,
725 {},
726 } );
727
728 const std::vector<VECTOR2I>& directions = m_snapLineManager.GetDirections();
729 const std::optional<int> activeDirection = m_snapLineManager.GetActiveDirection();
730
731 for( size_t ii = 0; ii < directions.size(); ++ii )
732 {
733 const VECTOR2I& direction = directions[ii];
734
735 VECTOR2I scaledDirection = direction * 100000;
736
738 entry.Drawable = LINE{ *snapLineOrigin, *snapLineOrigin + scaledDirection };
739 entry.LineWidth = ( activeDirection && *activeDirection == static_cast<int>( ii ) ) ? 2 : 1;
740
741 snapPointItem.Constructions.push_back( entry );
742 }
743
744 if( !snapPointItem.Constructions.empty() )
745 batches.push_back( std::move( batch ) );
746 }
747
748 return batches;
749}
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:990
void onTimerExpiry(wxTimerEvent &aEvent)
Timer expiry callback in the UI thread.
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.
Definition color4d.h:104
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
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()
double AsDegrees() const
Definition eda_angle.h:116
A base class for most all the KiCad significant classes used in schematics and boards.
Definition eda_item.h:98
A color representation with 4 components: red, green, blue, alpha.
Definition color4d.h:104
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)
Definition line.h:36
Definition seg.h:42
void SetDirections(const std::vector< VECTOR2I > &aDirections)
void SetSnappedAnchor(const VECTOR2I &aAnchorPos)
Inform this manager that an anchor snap has been made.
OPT_VECTOR2I GetNearestSnapLinePoint(const VECTOR2I &aCursor, const VECTOR2I &aNearestGrid, std::optional< int > aDistToNearest, int snapRange) const
If the snap line is active, return the best snap point that is closest to the cursor.
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.
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).
Definition vector2d.h:283
@ WHITE
Definition color4d.h:48
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)
@ DEGREES_T
Definition eda_angle.h:31
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
Definition hash.h:32
static constexpr std::size_t hash_val(const Types &... args)
Definition hash.h:51
The Cairo implementation of the graphics abstraction layer.
Definition eda_group.h:33
STL namespace.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
std::optional< VECTOR2I > OPT_VECTOR2I
Definition seg.h:39
KIGFX::CONSTRUCTION_GEOM::DRAWABLE Drawable
int LineWidth
Items to be used for the construction of "virtual" anchors, for example, when snapping to a point inv...
std::vector< DRAWABLE_ENTRY > Constructions
int delta
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694