Skip creating an automatic H/V constraint if it would be redundant.

This means that automatically added H/V constraints now will never
cause the sketch to become overconstrained, which currently makes
that feature almost unusable.
pull/434/head
whitequark 2019-05-24 15:06:53 +00:00
parent 394c1f62d8
commit 549565958f
4 changed files with 34 additions and 23 deletions

View File

@ -37,6 +37,8 @@ New constraint features:
Values are edited in the configured unit regardless of label format. Values are edited in the configured unit regardless of label format.
* It is now possible to turn off automatic creation of horizontal/vertical * It is now possible to turn off automatic creation of horizontal/vertical
constraints on line segments. constraints on line segments.
* Automatic creation of constraints no longer happens if the constraint
would have been redundant with other ones.
New export/import features: New export/import features:
* Three.js: allow configuring projection for exported model, and initially * Three.js: allow configuring projection for exported model, and initially

View File

@ -75,10 +75,6 @@ void Constraint::DeleteAllConstraintsFor(Constraint::Type type, hEntity entityA,
SS.GW.hover.Clear(); SS.GW.hover.Clear();
} }
hConstraint Constraint::AddConstraint(Constraint *c) {
return AddConstraint(c, /*rememberForUndo=*/true);
}
hConstraint Constraint::AddConstraint(Constraint *c, bool rememberForUndo) { hConstraint Constraint::AddConstraint(Constraint *c, bool rememberForUndo) {
if(rememberForUndo) SS.UndoRemember(); if(rememberForUndo) SS.UndoRemember();
@ -91,8 +87,8 @@ hConstraint Constraint::AddConstraint(Constraint *c, bool rememberForUndo) {
} }
hConstraint Constraint::Constrain(Constraint::Type type, hEntity ptA, hEntity ptB, hConstraint Constraint::Constrain(Constraint::Type type, hEntity ptA, hEntity ptB,
hEntity entityA, hEntity entityB, hEntity entityA, hEntity entityB,
bool other, bool other2) bool other, bool other2)
{ {
Constraint c = {}; Constraint c = {};
c.group = SS.GW.activeGroup; c.group = SS.GW.activeGroup;
@ -107,8 +103,17 @@ hConstraint Constraint::Constrain(Constraint::Type type, hEntity ptA, hEntity pt
return AddConstraint(&c, /*rememberForUndo=*/false); return AddConstraint(&c, /*rememberForUndo=*/false);
} }
hConstraint Constraint::Constrain(Constraint::Type type, hEntity ptA, hEntity ptB, hEntity entityA){ hConstraint Constraint::TryConstrain(Constraint::Type type, hEntity ptA, hEntity ptB,
return Constrain(type, ptA, ptB, entityA, Entity::NO_ENTITY, /*other=*/false, /*other2=*/false); hEntity entityA, hEntity entityB,
bool other, bool other2) {
SolveResult solvedBefore = SS.TestRankForGroup(SS.GW.activeGroup);
hConstraint hc = Constrain(type, ptA, ptB, entityA, entityB, other, other2);
SolveResult solvedAfter = SS.TestRankForGroup(SS.GW.activeGroup);
if(solvedBefore == SolveResult::OKAY && solvedAfter == SolveResult::REDUNDANT_OKAY) {
SK.constraint.RemoveById(hc);
hc = {};
}
return hc;
} }
hConstraint Constraint::ConstrainCoincident(hEntity ptA, hEntity ptB) { hConstraint Constraint::ConstrainCoincident(hEntity ptA, hEntity ptB) {

View File

@ -526,7 +526,7 @@ void GraphicsWindow::MouseRightUp(double x, double y) {
if(context.active) return; if(context.active) return;
if(pending.operation == Pending::DRAGGING_NEW_LINE_POINT && pending.hasSuggestion) { if(pending.operation == Pending::DRAGGING_NEW_LINE_POINT && pending.hasSuggestion) {
Constraint::Constrain(SS.GW.pending.suggestion, Constraint::TryConstrain(SS.GW.pending.suggestion,
Entity::NO_ENTITY, Entity::NO_ENTITY, pending.request.entity(0)); Entity::NO_ENTITY, Entity::NO_ENTITY, pending.request.entity(0));
} }
@ -943,7 +943,8 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
} }
// This will be clobbered by MouseMoved below. // This will be clobbered by MouseMoved below.
bool hasConstraintSuggestion = SS.GW.pending.hasSuggestion; bool hasConstraintSuggestion = pending.hasSuggestion;
Constraint::Type constraintSuggestion = pending.suggestion;
// Make sure the hover is up to date. // Make sure the hover is up to date.
MouseMoved(mx, my, /*leftDown=*/false, /*middleDown=*/false, /*rightDown=*/false, MouseMoved(mx, my, /*leftDown=*/false, /*middleDown=*/false, /*rightDown=*/false,
@ -1223,12 +1224,6 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
} }
case Pending::DRAGGING_NEW_LINE_POINT: { case Pending::DRAGGING_NEW_LINE_POINT: {
// Constrain the line segment horizontal or vertical if close enough
if(hasConstraintSuggestion) {
Constraint::Constrain(SS.GW.pending.suggestion,
Entity::NO_ENTITY, Entity::NO_ENTITY, pending.request.entity(0));
}
if(hover.entity.v) { if(hover.entity.v) {
Entity *e = SK.GetEntity(hover.entity); Entity *e = SK.GetEntity(hover.entity);
if(e->IsPoint()) { if(e->IsPoint()) {
@ -1246,7 +1241,15 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
} }
} }
if(ConstrainPointByHovered(pending.point, &mouse)) { bool doneDragging = ConstrainPointByHovered(pending.point, &mouse);
// Constrain the line segment horizontal or vertical if close enough
if(hasConstraintSuggestion) {
Constraint::TryConstrain(constraintSuggestion,
Entity::NO_ENTITY, Entity::NO_ENTITY, pending.request.entity(0));
}
if(doneDragging) {
ClearPending(); ClearPending();
break; break;
} }

View File

@ -727,16 +727,17 @@ public:
std::string DescriptionString() const; std::string DescriptionString() const;
static hConstraint AddConstraint(Constraint *c, bool rememberForUndo); static hConstraint AddConstraint(Constraint *c, bool rememberForUndo = true);
static hConstraint AddConstraint(Constraint *c);
static void MenuConstrain(Command id); static void MenuConstrain(Command id);
static void DeleteAllConstraintsFor(Constraint::Type type, hEntity entityA, hEntity ptA); static void DeleteAllConstraintsFor(Constraint::Type type, hEntity entityA, hEntity ptA);
static hConstraint ConstrainCoincident(hEntity ptA, hEntity ptB); static hConstraint ConstrainCoincident(hEntity ptA, hEntity ptB);
static hConstraint Constrain(Constraint::Type type, hEntity ptA, hEntity ptB, hEntity entityA); static hConstraint Constrain(Constraint::Type type, hEntity ptA, hEntity ptB, hEntity entityA,
static hConstraint Constrain(Constraint::Type type, hEntity ptA, hEntity ptB, hEntity entityB = Entity::NO_ENTITY, bool other = false,
hEntity entityA, hEntity entityB, bool other2 = false);
bool other, bool other2); static hConstraint TryConstrain(Constraint::Type type, hEntity ptA, hEntity ptB,
hEntity entityA, hEntity entityB = Entity::NO_ENTITY,
bool other = false, bool other2 = false);
}; };
class hEquation { class hEquation {