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 )
364 bool overBadge = std::ranges::any_of( layout,
366 {
return ( aPos -
VECTOR2D(
cursor ) ).EuclideanNorm() <= badgeTol; } );
400 std::unordered_set<KIID> constrained;
403 constrained.insert( entry.first );
420 std::unordered_set<KIID> members;
425 members.insert( member.m_item );
437 const std::unordered_set<KIID>& aNew )
450 for(
const KIID&
id : aOld )
452 if( !aNew.contains(
id ) )
456 for(
const KIID&
id : aNew )
458 if( !aOld.contains(
id ) )
474 if(
PANEL_CONSTRAINTS* panel = pcbFrame->GetConstraintsPanel(); panel && panel->IsShownOnScreen() )
475 panel->RefreshList( aDiag );
483 std::vector<PCB_SHAPE*> members;
488 members.push_back( shape );
492 commit.
Remove( aConstraint );
493 commit.
Push(
_(
"Remove Geometric Constraint" ) );
570 const std::vector<CONSTRAINT_MEMBER>& members = constraint->
GetMembers();
573 bool highlightOne = aMemberIndex >= 0 && aMemberIndex < static_cast<int>( members.size() );
582 selectMember( members[aMemberIndex] );
584 std::ranges::for_each( members, selectMember );
601 return std::ranges::all_of( aConstraint->
GetMembers(),
604 BOARD_ITEM* item = board()->ResolveItem( aMember.m_item, true );
605 return item && ConstraintItemIsLocked( item );
612 if( !aConstraint || !
board() )
617 return std::ranges::any_of( aList,
624 if( scan(
board()->Constraints() ) )
632 const std::vector<PCB_CONSTRAINT*>& aAdded )
634 aCommit.
Push(
_(
"Add Geometric Constraint" ) );
637 if( !aAdded.empty() )
642 if( aAdded.empty() || !
frame() )
652 frame()->ShowInfoBarWarning(
_(
"All items referenced by this constraint are locked, so the constraint cannot "
653 "move any geometry." ),
667 frame()->ShowInfoBarWarning(
_(
"The new geometric constraint conflicts with existing constraints and "
668 "could not be satisfied." ),
675 frame()->ShowInfoBarWarning(
_(
"The new geometric constraint could not be applied to the referenced "
738 std::vector<PCB_SHAPE*> modified;
741 board(), aConstraint, &modified,
749 if( !commit.
Empty() )
760 std::vector<PCB_SHAPE*> modified;
768 if( !commit.
Empty() )
781 std::vector<PCB_SHAPE*> modified;
789 if( !commit.
Empty() )
809 bool overConstrained = std::ranges::any_of( aShapes,
816 if( overConstrained &&
frame() )
817 frame()->ShowInfoBarWarning(
_(
"A geometric constraint could not be satisfied by this edit." ),
true );
838 frame()->GetPcbNewSettings()->m_Display.m_ShowConstraints = always;
852 pcbFrame->ToggleConstraintsPanel();
923 return static_cast<const PCB_SHAPE*
>( aItem )->GetShape();
927 auto isRadial = [](
SHAPE_T aShape )
932 auto isCentered = [isRadial](
SHAPE_T aShape )
937 auto oneRadial = [kindOf, isRadial](
const SELECTION& aSel )
939 return aSel.Size() == 1 && isRadial( kindOf( aSel[0] ) );
942 auto oneArc = [kindOf](
const SELECTION& aSel )
944 return aSel.Size() == 1 && kindOf( aSel[0] ) ==
SHAPE_T::ARC;
947 auto twoRadial = [kindOf, isRadial](
const SELECTION& aSel )
949 return aSel.Size() == 2 && isRadial( kindOf( aSel[0] ) ) && isRadial( kindOf( aSel[1] ) );
952 auto twoCentered = [kindOf, isCentered](
const SELECTION& aSel )
954 return aSel.Size() == 2 && isCentered( kindOf( aSel[0] ) ) && isCentered( kindOf( aSel[1] ) );
958 auto tangentPair = [kindOf, isCentered, isRadial](
const SELECTION& aSel )
960 if( aSel.Size() != 2 )
967 || ( isRadial( a ) && isRadial( b ) );
971 auto selectionConstrained = [
this](
const SELECTION& aSel ) ->
bool
973 if( aSel.Empty() || !
board() )
979 ids.insert( item->m_Uuid );
983 return std::ranges::any_of( aList,
991 if( anyMember(
board()->Constraints() ) )
995 && anyMember(
board()->GetFirstFootprint()->Constraints() );
1003 m_menu->SetUntranslatedTitle(
_HKI(
"Constraints" ) );
1009 const std::map<const TOOL_ACTION*, SELECTION_CONDITION> gate = {
1025 bool pointGroupSeparated =
false;
1029 if(
auto it = gate.find( action ); it != gate.end() )
1031 m_menu->AddItem( *action, it->second );
1035 if( !pointGroupSeparated )
1038 pointGroupSeparated =
true;
1049 auto overlayShown = [
this](
const SELECTION& )
1053 auto overlayHidden = [
this](
const SELECTION& )
1076 std::vector<BOARD_ITEM*> items;
1080 if( item->IsBOARD_ITEM() )
1081 items.push_back(
static_cast<BOARD_ITEM*
>( item ) );
1084 std::unique_ptr<PCB_CONSTRAINT> constraint =
1093 if( !items.empty() &&
frame() )
1096 frame()->ShowInfoBarWarning( hint );
1120 frame()->ShowInfoBarWarning(
_(
"An identical geometric constraint already exists." ) );
1127 if( aConstraint->HasValue() )
1135 bool driving = aConstraint->IsDriving();
1138 driving = it->second;
1155 commit.
Add( aConstraint.release() );
1165 bool allowCircle =
false;
1173 allowCircle =
false;
1188 allowCircle =
false;
1197 std::vector<KIID> picked;
1198 const double snapTol =
pcbIUScale.mmToIU( 1.0 );
1206 [&](
const VECTOR2D& aPoint ) ->
bool
1214 picked.push_back( *target );
1216 if(
static_cast<int>( picked.size() ) < count )
1226 std::vector<BOARD_ITEM*> items;
1228 for(
const KIID&
id : picked )
1231 items.push_back( item );
1234 std::unique_ptr<PCB_CONSTRAINT> constraint =
1237 if( !constraint &&
frame() )
1239 frame()->ShowInfoBarWarning( wxString::Format(
_(
"Cannot form a %s constraint from those items." ),
1263 m_overlay->SetPickPreview( target.value_or(
niluuid ),
true, std::nullopt );
1279 evt->SetPassEvent();
1301 std::vector<CONSTRAINT_MEMBER> members;
1302 const double snapTol =
pcbIUScale.mmToIU( 1.0 );
1309 auto commitPointPair = [&]()
1311 std::unique_ptr<PCB_CONSTRAINT> constraint =
1315 constraint->AddMember( member.m_item, member.m_anchor, member.m_index );
1321 [&](
const VECTOR2D& aPoint ) ->
bool
1327 std::optional<CONSTRAINT_MEMBER>
anchor =
1332 members.push_back( *
anchor );
1334 if( members.size() < 2 )
1349 if( members.empty() )
1353 std::unique_ptr<PCB_CONSTRAINT> constraint =
1372 if( std::optional<CONSTRAINT_MEMBER>
anchor =
1378 else if( members.empty() )
1381 m_overlay->SetPickPreview( *target,
true, std::nullopt );
1404 evt->SetPassEvent();
1423 std::vector<bool>
plan;
1440 std::vector<CONSTRAINT_MEMBER> members;
1441 const double snapTol =
pcbIUScale.mmToIU( 1.0 );
1449 [&](
const VECTOR2D& aPoint ) ->
bool
1453 if(
plan[members.size()] )
1457 std::optional<CONSTRAINT_MEMBER>
anchor =
1463 members.push_back( *
anchor );
1467 std::optional<KIID> target =
1476 if( members.size() <
plan.size() )
1486 std::unique_ptr<PCB_CONSTRAINT> constraint =
1490 constraint->AddMember( member.m_item, member.m_anchor, member.m_index );
1495 frame()->ShowInfoBarWarning(
_(
"An identical geometric constraint already exists." ) );
1503 commit.
Add( constraint.release() );
1520 std::optional<VECTOR2I> anchorPos;
1522 if(
plan[members.size()] )
1524 if( std::optional<CONSTRAINT_MEMBER>
anchor =
1527 element =
anchor->m_item;
1538 m_overlay->SetPickPreview( element, whole, anchorPos );
1544 [&](
const int& aFinalState )
1555 evt->SetPassEvent();
1572 std::set<KIID> selectedIds;
1575 selectedIds.insert( item->m_Uuid );
1577 if( selectedIds.empty() )
1583 auto removeReferencing =
1588 bool referenced = std::ranges::any_of( constraint->GetMembers(),
1590 { return selectedIds.contains( aMember.m_item ); } );
1594 commit.
Remove( constraint );
1602 removeReferencing(
board()->Constraints() );
1605 removeReferencing(
board()->GetFirstFootprint()->Constraints() );
1609 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
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_ITEM objects.
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.
std::optional< KIID > NearestConstrainedShape(const BOARD *aBoard, const std::vector< KIID > &aCandidates, const VECTOR2I &aPos, int aMaxDist)
The candidate shape whose outline aPos hits within aMaxDist, or std::nullopt.
std::optional< KIID > NearestOutlineShape(const BOARD *aBoard, const VECTOR2I &aPos, double aMaxDist, bool aAllowCircle, PCB_LAYER_ID aLayer)
The shape whose outline is nearest aPos within aMaxDist.
std::vector< KIID > ConstrainedShapeIds(const BOARD *aBoard)
The member ids of every board and footprint constraint that are on aBoard, in first reference order: ...
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< CONSTRAINT_MEMBER > NearestConstraintAnchor(const BOARD *aBoard, const VECTOR2I &aPos, double aMaxDist, const std::vector< CONSTRAINT_MEMBER > &aExclude, PCB_LAYER_ID aLayer)
Find the constrainable-item anchor (a shape's segment/arc endpoint or centre, or a dimension's featur...
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< VECTOR2I > ConstraintAnchorPosition(const 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...
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).
static std::vector< PENDING_PROPERTY > plan(const EDA_ITEM &aSource, const EDA_ITEM &aTarget, const std::set< wxString > &aEnabledKeys)
Target properties to write, paired with values read off the source.
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