102 m_overlay->SetVisibilityMode(
frame()->GetPcbNewSettings()->m_Display.m_ShowConstraints
136 const std::vector<CONSTRAINT_BADGE>& badges =
m_overlay->Badges();
140 for(
size_t i = 0; i < badges.size(); ++i )
142 double dist = ( layout[i] -
VECTOR2D( aPos ) ).EuclideanNorm();
171 panel->SelectConstraint( aConstraint->
m_Uuid );
184 if( !aConstraint || !
board() )
194 std::vector<MSG_PANEL_ITEM> items;
202 if( !members.IsEmpty() )
203 members += wxT(
", " );
208 items.emplace_back(
_(
"Items" ), members );
211 wxString state =
_(
"OK" );
214 state =
_(
"Error (missing item)" );
216 state =
_(
"Over-constrained" );
218 state =
_(
"Redundant" );
220 items.emplace_back(
_(
"State" ), state );
222 frame()->SetMsgPanel( items );
288 panel = pcbFrame->GetConstraintsPanel();
290 bool panelShown = panel && panel->IsShownOnScreen();
298 if( !overlayActive && !panelShown )
336 std::vector<PCB_SHAPE*> shapes;
345 if( ids.insert( m.m_item ).second )
348 dynamic_cast<PCB_SHAPE*
>(
board()->ResolveItem( m.m_item,
true ) ) )
350 shapes.push_back( shape );
359 collect(
board()->Constraints() );
395 bool overBadge = std::ranges::any_of( layout,
397 {
return ( aPos -
VECTOR2D(
cursor ) ).EuclideanNorm() <= badgeTol; } );
431 std::unordered_set<KIID> constrained;
434 constrained.insert( entry.first );
451 std::unordered_set<KIID> members;
456 members.insert( member.m_item );
468 const std::unordered_set<KIID>& aNew )
481 for(
const KIID&
id : aOld )
483 if( !aNew.contains(
id ) )
487 for(
const KIID&
id : aNew )
489 if( !aOld.contains(
id ) )
505 if(
PANEL_CONSTRAINTS* panel = pcbFrame->GetConstraintsPanel(); panel && panel->IsShownOnScreen() )
506 panel->RefreshList( aDiag );
514 std::vector<PCB_SHAPE*> members;
519 members.push_back( shape );
523 commit.
Remove( aConstraint );
524 commit.
Push(
_(
"Remove Geometric Constraint" ) );
601 const std::vector<CONSTRAINT_MEMBER>& members = constraint->
GetMembers();
604 bool highlightOne = aMemberIndex >= 0 && aMemberIndex < static_cast<int>( members.size() );
613 selectMember( members[aMemberIndex] );
615 std::ranges::for_each( members, selectMember );
632 return std::ranges::all_of( aConstraint->
GetMembers(),
635 BOARD_ITEM* item = board()->ResolveItem( aMember.m_item, true );
636 return item && ConstraintItemIsLocked( item );
643 if( !aConstraint || !
board() )
648 return std::ranges::any_of( aList,
655 if( scan(
board()->Constraints() ) )
663 const std::vector<PCB_CONSTRAINT*>& aAdded )
665 aCommit.
Push(
_(
"Add Geometric Constraint" ) );
668 if( !aAdded.empty() )
673 if( aAdded.empty() || !
frame() )
683 frame()->ShowInfoBarWarning(
_(
"All items referenced by this constraint are locked, so the constraint cannot "
684 "move any geometry." ),
698 frame()->ShowInfoBarWarning(
_(
"The new geometric constraint conflicts with existing constraints and "
699 "could not be satisfied." ),
706 frame()->ShowInfoBarWarning(
_(
"The new geometric constraint could not be applied to the referenced "
769 std::vector<PCB_SHAPE*> modified;
772 board(), aConstraint, &modified,
780 if( !commit.
Empty() )
791 std::vector<PCB_SHAPE*> modified;
799 if( !commit.
Empty() )
812 std::vector<PCB_SHAPE*> modified;
820 if( !commit.
Empty() )
840 bool overConstrained = std::ranges::any_of( aShapes,
847 if( overConstrained &&
frame() )
848 frame()->ShowInfoBarWarning(
_(
"A geometric constraint could not be satisfied by this edit." ),
true );
869 frame()->GetPcbNewSettings()->m_Display.m_ShowConstraints = always;
883 pcbFrame->ToggleConstraintsPanel();
954 return static_cast<const PCB_SHAPE*
>( aItem )->GetShape();
958 auto isRadial = [](
SHAPE_T aShape )
963 auto isCentered = [isRadial](
SHAPE_T aShape )
968 auto oneRadial = [kindOf, isRadial](
const SELECTION& aSel )
970 return aSel.Size() == 1 && isRadial( kindOf( aSel[0] ) );
973 auto oneArc = [kindOf](
const SELECTION& aSel )
975 return aSel.Size() == 1 && kindOf( aSel[0] ) ==
SHAPE_T::ARC;
978 auto twoRadial = [kindOf, isRadial](
const SELECTION& aSel )
980 return aSel.Size() == 2 && isRadial( kindOf( aSel[0] ) ) && isRadial( kindOf( aSel[1] ) );
983 auto twoCentered = [kindOf, isCentered](
const SELECTION& aSel )
985 return aSel.Size() == 2 && isCentered( kindOf( aSel[0] ) ) && isCentered( kindOf( aSel[1] ) );
989 auto tangentPair = [kindOf, isCentered, isRadial](
const SELECTION& aSel )
991 if( aSel.Size() != 2 )
998 || ( isRadial( a ) && isRadial( b ) );
1002 auto selectionConstrained = [
this](
const SELECTION& aSel ) ->
bool
1004 if( aSel.Empty() || !
board() )
1010 ids.insert( item->m_Uuid );
1014 return std::ranges::any_of( aList,
1022 if( anyMember(
board()->Constraints() ) )
1026 && anyMember(
board()->GetFirstFootprint()->Constraints() );
1034 m_menu->SetUntranslatedTitle(
_HKI(
"Constraints" ) );
1040 const std::map<const TOOL_ACTION*, SELECTION_CONDITION> gate = {
1056 bool pointGroupSeparated =
false;
1060 if(
auto it = gate.find( action ); it != gate.end() )
1062 m_menu->AddItem( *action, it->second );
1066 if( !pointGroupSeparated )
1069 pointGroupSeparated =
true;
1080 auto overlayShown = [
this](
const SELECTION& )
1084 auto overlayHidden = [
this](
const SELECTION& )
1107 std::vector<BOARD_ITEM*> items;
1111 if( item->IsBOARD_ITEM() )
1112 items.push_back(
static_cast<BOARD_ITEM*
>( item ) );
1115 std::unique_ptr<PCB_CONSTRAINT> constraint =
1124 if( !items.empty() &&
frame() )
1127 frame()->ShowInfoBarWarning( hint );
1151 frame()->ShowInfoBarWarning(
_(
"An identical geometric constraint already exists." ) );
1158 if( aConstraint->HasValue() )
1166 bool driving = aConstraint->IsDriving();
1169 driving = it->second;
1186 commit.
Add( aConstraint.release() );
1196 bool allowCircle =
false;
1204 allowCircle =
false;
1219 allowCircle =
false;
1228 std::vector<KIID> picked;
1229 const double snapTol =
pcbIUScale.mmToIU( 1.0 );
1237 [&](
const VECTOR2D& aPoint ) ->
bool
1245 picked.push_back( *target );
1247 if(
static_cast<int>( picked.size() ) < count )
1257 std::vector<BOARD_ITEM*> items;
1259 for(
const KIID&
id : picked )
1262 items.push_back( item );
1265 std::unique_ptr<PCB_CONSTRAINT> constraint =
1268 if( !constraint &&
frame() )
1270 frame()->ShowInfoBarWarning( wxString::Format(
_(
"Cannot form a %s constraint from those items." ),
1294 m_overlay->SetPickPreview( target.value_or(
niluuid ),
true, std::nullopt );
1310 evt->SetPassEvent();
1332 std::vector<CONSTRAINT_MEMBER> members;
1333 const double snapTol =
pcbIUScale.mmToIU( 1.0 );
1340 auto commitPointPair = [&]()
1342 std::unique_ptr<PCB_CONSTRAINT> constraint =
1346 constraint->AddMember( member.m_item, member.m_anchor, member.m_index );
1352 [&](
const VECTOR2D& aPoint ) ->
bool
1358 std::optional<CONSTRAINT_MEMBER>
anchor =
1363 members.push_back( *
anchor );
1365 if( members.size() < 2 )
1380 if( members.empty() )
1384 std::unique_ptr<PCB_CONSTRAINT> constraint =
1403 if( std::optional<CONSTRAINT_MEMBER>
anchor =
1409 else if( members.empty() )
1412 m_overlay->SetPickPreview( *target,
true, std::nullopt );
1435 evt->SetPassEvent();
1454 std::vector<bool> plan;
1471 std::vector<CONSTRAINT_MEMBER> members;
1472 const double snapTol =
pcbIUScale.mmToIU( 1.0 );
1480 [&](
const VECTOR2D& aPoint ) ->
bool
1484 if( plan[members.size()] )
1488 std::optional<CONSTRAINT_MEMBER>
anchor =
1494 members.push_back( *
anchor );
1498 std::optional<KIID> target =
1507 if( members.size() < plan.size() )
1517 std::unique_ptr<PCB_CONSTRAINT> constraint =
1521 constraint->AddMember( member.m_item, member.m_anchor, member.m_index );
1526 frame()->ShowInfoBarWarning(
_(
"An identical geometric constraint already exists." ) );
1534 commit.
Add( constraint.release() );
1544 if( !
m_overlay || members.size() >= plan.size() )
1551 std::optional<VECTOR2I> anchorPos;
1553 if( plan[members.size()] )
1555 if( std::optional<CONSTRAINT_MEMBER>
anchor =
1558 element =
anchor->m_item;
1569 m_overlay->SetPickPreview( element, whole, anchorPos );
1575 [&](
const int& aFinalState )
1586 evt->SetPassEvent();
1603 std::set<KIID> selectedIds;
1606 selectedIds.insert( item->m_Uuid );
1608 if( selectedIds.empty() )
1614 auto removeReferencing =
1619 bool referenced = std::ranges::any_of( constraint->GetMembers(),
1621 { return selectedIds.contains( aMember.m_item ); } );
1625 commit.
Remove( constraint );
1633 removeReferencing(
board()->Constraints() );
1636 removeReferencing(
board()->GetFirstFootprint()->Constraints() );
1640 commit.
Push(
_(
"Remove Geometric Constraints" ) );
constexpr EDA_IU_SCALE pcbIUScale
std::set< KIID > ConstraintReferenceShapes(BOARD *aBoard, const PCB_CONSTRAINT *aConstraint)
The shapes a just-authored constraint should treat as an immovable reference, for the caller to pass ...
bool BoardHasConstraints(BOARD *aBoard)
True if the board or any of its footprints carries at least one geometric constraint.
CONSTRAINT_DIAGNOSIS ApplyConstraintImmediately(BOARD *aBoard, const PCB_CONSTRAINT *aConstraint, std::vector< PCB_SHAPE * > *aModified, const std::function< void(BOARD_ITEM *)> &aBeforeModify, const std::set< KIID > &aFixedShapes)
Solve a just-created constraint's cluster so the geometry snaps to satisfy it (SolidWorks-style),...
void ReSolveShapeClusters(BOARD *aBoard, const std::vector< PCB_SHAPE * > &aShapes, std::vector< PCB_SHAPE * > *aModified, const std::function< void(BOARD_ITEM *)> &aBeforeModify)
Re-solve the clusters of shapes edited outside the solver, e.g.
bool ReSolveShapeClustersHoldingEdited(BOARD *aBoard, const std::vector< PCB_SHAPE * > &aEditedShapes, std::vector< PCB_SHAPE * > *aModified, const std::function< void(BOARD_ITEM *)> &aBeforeModify)
Re-solve clusters whose new geometry is authoritative holding every edited shape fully fixed so only ...
@ OVER_CONSTRAINED
In a cluster the solver reports as conflicting.
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
static TOOL_ACTION pickerTool
static TOOL_ACTION zoomFitSelection
virtual void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
FOOTPRINT * GetFirstFootprint() const
Get the first footprint on the board or nullptr.
BOARD_ITEM * ResolveItem(const KIID &aID, bool aAllowNullptrReturn=false) const
COMMIT & Remove(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Remove a new item from the model.
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
COMMIT & Add(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr)
Add a new item to the model.
static double BadgeHitRadius()
Click hit radius in screen pixels.
static double BadgeWorldPerPixel(double aWorldScale)
World units per screen pixel for badge sizing, capped at far zoom-out.
static std::vector< VECTOR2D > LayoutBadges(const std::vector< CONSTRAINT_BADGE > &aBadges, double aWorldPerPx)
The on-screen draw position (world units) of each badge at the given scale: the anchor offset by Badg...
Lists every geometric constraint on the board with its type and diagnostic state, the way the canvas ...
Value entry for a dimensional geometric constraint (issue #2329): a UNIT_BINDER for the length (or an...
bool GetDriving() const
True if the constraint should drive (lock) the geometry; false for a reference dimension.
double GetConstraintValue()
The entered value, in IU for a length/radius or in degrees for an angle.
A base class for most all the KiCad significant classes used in schematics and boards.
static const TOOL_EVENT ClearedEvent
static const TOOL_EVENT SelectedEvent
static const TOOL_EVENT UndoRedoPostEvent
static const TOOL_EVENT UnselectedEvent
virtual RENDER_SETTINGS * GetSettings()=0
Return a pointer to current settings that are going to be used when drawing items.
PCB specific render settings.
void SetHighlightedConstraintMembers(std::unordered_set< KIID > aItems)
void SetConstrainedItems(std::unordered_set< KIID > aItems)
const std::unordered_set< KIID > & GetHighlightedConstraintMembers() const
const std::unordered_set< KIID > & GetConstrainedItems() const
virtual VECTOR2D GetMousePosition(bool aWorldCoordinates=true) const =0
Return the current mouse pointer position.
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...
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.
Dockable panel listing the board's geometric constraints (issue #2329).
static TOOL_ACTION hideConstraints
Same toggle, shown while the overlay is visible.
static TOOL_ACTION addConstraintVertical
static TOOL_ACTION addConstraintPerpendicular
static TOOL_ACTION addConstraintAngular
static TOOL_ACTION addConstraintArcAngle
static TOOL_ACTION manageConstraints
Open the constraint list dialog.
static TOOL_ACTION addConstraintHorizontal
static const std::vector< const TOOL_ACTION * > & ConstraintAddActions()
Canonical ordered list of the geometric-constraint "add" actions, shared by the context submenu (gate...
static TOOL_ACTION addConstraintCollinear
static TOOL_ACTION addConstraintEqualRadius
static TOOL_ACTION addConstraintTangent
static TOOL_ACTION addConstraintFixedLength
static TOOL_ACTION toggleAutoConstraints
Toggle authoring constraints automatically while drawing.
static TOOL_ACTION addConstraintSymmetric
static TOOL_ACTION addConstraintFixedPosition
Ground a point, and the cluster holding it.
static TOOL_ACTION addConstraintPointOnLine
static TOOL_ACTION addConstraintCoincident
static TOOL_ACTION showConstraints
Toggle the constraint diagnostics overlay.
static TOOL_ACTION addConstraintParallel
static TOOL_ACTION addConstraintFixedRadius
static TOOL_ACTION addConstraintEqualLength
static TOOL_ACTION removeConstraints
static TOOL_ACTION addConstraintMidpoint
static TOOL_ACTION addConstraintConcentric
A geometric constraint between board items (issue #2329).
const std::vector< CONSTRAINT_MEMBER > & GetMembers() const
std::optional< double > GetValue() const
bool IsDriving() const
A driving constraint forces its value; a reference (non-driving) one only measures it.
PCB_CONSTRAINT_TYPE GetConstraintType() const
The main frame for Pcbnew.
Class that groups generic conditions for selected items.
static SELECTION_CONDITION Count(int aNumber)
Create a functor that tests if the number of selected items is equal to the value given as parameter.
static bool ShowAlways(const SELECTION &aSelection)
The default condition function (always returns true).
static SELECTION_CONDITION OnlyTypes(std::vector< KICAD_T > aTypes)
Create a functor that tests if the selected items are only of given types.
A type-safe container of any type.
double InitialConstraintValue(PCB_CONSTRAINT_TYPE aType, double aMeasured, const std::map< PCB_CONSTRAINT_TYPE, double > &aRemembered)
Value a freshly authored constraint dialog should open with.
std::optional< KIID > NearestConstrainedShape(const std::vector< PCB_SHAPE * > &aCandidates, const VECTOR2I &aPos, int aMaxDist)
The candidate shape whose outline aPos hits within aMaxDist, or std::nullopt.
wxString ConstraintSelectionHint(PCB_CONSTRAINT_TYPE aType)
A sentence naming what aType needs selected, for the moment a selection does not fit it and the tool ...
std::unique_ptr< PCB_CONSTRAINT > BuildConstraintFromItems(BOARD_ITEM *aParent, PCB_CONSTRAINT_TYPE aType, const std::vector< BOARD_ITEM * > &aItems)
Build a constraint of aType from a set of selected board items, or nullptr if the selection does not ...
std::optional< KIID > NearestOutlineShape(BOARD *aBoard, const VECTOR2I &aPos, double aMaxDist, bool aAllowCircle)
The shape whose outline is nearest aPos within aMaxDist.
std::optional< VECTOR2I > ConstraintAnchorPosition(BOARD *aBoard, const CONSTRAINT_MEMBER &aMember)
Current location of a constraint member's anchor (its shape's START/END/CENTER, or a dimension's feat...
std::optional< CONSTRAINT_MEMBER > NearestConstraintAnchor(BOARD *aBoard, const VECTOR2I &aPos, double aMaxDist, const std::vector< CONSTRAINT_MEMBER > &aExclude)
Find the constrainable-item anchor (a shape's segment/arc endpoint or centre, or a dimension's featur...
bool EditConstraintValue(PCB_BASE_FRAME *aFrame, PCB_CONSTRAINT *aConstraint, BOARD_COMMIT &aCommit)
Show the value dialog for a valued constraint and stage the change in aCommit (the caller pushes).
Message panel definition file.
@ ALL
All except INITIAL_ADD.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
bool ConstraintsAreDuplicate(const PCB_CONSTRAINT &aA, const PCB_CONSTRAINT &aB)
True if two constraints express the same relation, meaning the same type and the same members compare...
wxString ConstraintTypeLabel(PCB_CONSTRAINT_TYPE aType)
Human-readable name of a constraint type (e.g. "Parallel"), for menus and lists.
wxString ConstraintMemberLabel(BOARD_ITEM *aItem, const CONSTRAINT_MEMBER &aMember, UNITS_PROVIDER *aUnitsProvider)
Label for one constrained item in a list combining the item description with its anchored feature suc...
wxString ConstraintDisplayLabel(const PCB_CONSTRAINT &aConstraint, EDA_UNITS aUnits)
Display label for a constraint in lists and menus.
@ WHOLE
The item as a whole (a segment as a line, a circle).
PCB_CONSTRAINT_TYPE
The geometric relationship a PCB_CONSTRAINT enforces between its members.
@ CONCENTRIC
Two arcs/circles share a center.
@ SYMMETRIC
Two points are mirror images about an axis.
@ FIXED_POSITION
A point is locked at its current location.
@ VERTICAL
A segment (or two points) is vertical.
@ TANGENT
A line and a curve, or two curves, touch tangentially.
@ COINCIDENT
Two points are made to coincide.
@ FIXED_RADIUS
An arc/circle has a driving radius value.
@ HORIZONTAL
A segment (or two points) is horizontal.
@ EQUAL_RADIUS
Two arcs/circles have equal radius.
@ MIDPOINT
A point is the midpoint of a segment.
@ POINT_ON_LINE
A point lies on a segment's supporting line.
@ FIXED_LENGTH
A segment has a driving length value.
@ ARC_ANGLE
An arc has a driving or reference swept-angle value.
std::deque< PCB_CONSTRAINT * > CONSTRAINTS
T * GetAppSettings(const char *aFilename)
Board-wide diagnostics for the constraint overlay and info bar.
std::map< KIID, CONSTRAINT_STATE > shapeStates
std::vector< KIID > errored
Invalid constraints (member missing, deleted, or of a kind incompatible with the type).
std::vector< KIID > redundant
std::vector< KIID > conflicting
One participant in a constraint: a referenced board item plus the feature of that item that participa...
wxString result
Test unit parsing edge cases and error handling.
@ PCB_SHAPE_T
class PCB_SHAPE, a segment not on copper layers
@ PCB_SHAPE_LOCATE_SEGMENT_T
VECTOR2< int32_t > VECTOR2I
VECTOR2< double > VECTOR2D