diff --git a/constraint.cpp b/constraint.cpp index 78f4d6ee..16128410 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -306,7 +306,7 @@ void Constraint::MenuConstrain(int id) { break; } - case GraphicsWindow::MNU_ORIENTED_SAME: + case GraphicsWindow::MNU_ORIENTED_SAME: { if(gs.anyNormals == 2 && gs.n == 2) { c.type = SAME_ORIENTATION; c.entityA = gs.anyNormal[0]; @@ -315,8 +315,36 @@ void Constraint::MenuConstrain(int id) { Error("Bad selection for same orientation constraint."); return; } - AddConstraint(&c); + SS.UndoRemember(); + + Entity *nfree = SS.GetEntity(c.entityA); + Entity *nref = SS.GetEntity(c.entityB); + if(nref->group.v == SS.GW.activeGroup.v) { + SWAP(Entity *, nref, nfree); + } + if(nfree->group.v == SS.GW.activeGroup.v && + nref ->group.v != SS.GW.activeGroup.v) + { + // nfree is free, and nref is locked (since it came from a + // previous group); so let's force nfree aligned to nref, + // and make convergence easy + Vector ru = nref ->NormalU(), rv = nref ->NormalV(); + Vector fu = nfree->NormalU(), fv = nfree->NormalV(); + + if(fabs(fu.Dot(ru)) < fabs(fu.Dot(rv))) { + // There might be an odd*90 degree rotation about the + // normal vector; allow that, since the numerical + // constraint does + SWAP(Vector, ru, rv); + } + fu = fu.Dot(ru) > 0 ? ru : ru.ScaledBy(-1); + fv = fv.Dot(rv) > 0 ? rv : rv.ScaledBy(-1); + + nfree->NormalForceTo(Quaternion::From(fu, fv)); + } + AddConstraint(&c, false); break; + } case GraphicsWindow::MNU_OTHER_ANGLE: if(gs.constraints == 1 && gs.n == 0) { diff --git a/draw.cpp b/draw.cpp index e5eef8de..6bcaeed1 100644 --- a/draw.cpp +++ b/draw.cpp @@ -775,7 +775,8 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) { Selection s; ZERO(&s); - // Do the entities + // Always do the entities; we might be dragging something that should + // be auto-constrained, and we need the hover for that. for(i = 0; i < SS.entity.n; i++) { Entity *e = &(SS.entity.elem[i]); // Don't hover whatever's being dragged. @@ -789,22 +790,25 @@ void GraphicsWindow::HitTestMakeSelection(Point2d mp) { } } - // Constraints - for(i = 0; i < SS.constraint.n; i++) { - d = SS.constraint.elem[i].GetDistance(mp); - if(d < 10 && d < dmin) { - memset(&s, 0, sizeof(s)); - s.constraint = SS.constraint.elem[i].h; - dmin = d; + // The constraints and faces happen only when nothing's in progress. + if(pending.operation == 0) { + // Constraints + for(i = 0; i < SS.constraint.n; i++) { + d = SS.constraint.elem[i].GetDistance(mp); + if(d < 10 && d < dmin) { + memset(&s, 0, sizeof(s)); + s.constraint = SS.constraint.elem[i].h; + dmin = d; + } } - } - // Faces, from the triangle mesh; these are lowest priority - if(s.constraint.v == 0 && s.entity.v == 0 && showShaded && showFaces) { - SMesh *m = &((SS.GetGroup(activeGroup))->mesh); - DWORD v = m->FirstIntersectionWith(mp); - if(v) { - s.entity.v = v; + // Faces, from the triangle mesh; these are lowest priority + if(s.constraint.v == 0 && s.entity.v == 0 && showShaded && showFaces) { + SMesh *m = &((SS.GetGroup(activeGroup))->mesh); + DWORD v = m->FirstIntersectionWith(mp); + if(v) { + s.entity.v = v; + } } }