From 10240cc1dfa39d00d817b76de124144b608f8f50 Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Thu, 8 May 2008 21:33:23 -0800 Subject: [PATCH] Add parallel and same orientation constraints, that work on line segments and normals. [git-p4: depot-paths = "//depot/solvespace/": change = 1713] --- constraint.cpp | 55 ++++++++++++++++++++++++++++++++++++++++++++++ drawconstraint.cpp | 29 ++++++++++++++++++++++++ entity.cpp | 46 ++++++++++++++++++++++++++++++++++++++ expr.cpp | 8 +++++++ expr.h | 2 ++ graphicswin.cpp | 18 +++++++++++++++ sketch.h | 7 ++++-- system.cpp | 14 ++++++++++++ ui.h | 6 +++++ 9 files changed, 183 insertions(+), 2 deletions(-) diff --git a/constraint.cpp b/constraint.cpp index 4907cee..b3345d9 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -181,6 +181,30 @@ void Constraint::MenuConstrain(int id) { break; } + case GraphicsWindow::MNU_ORIENTED_SAME: + if(gs.anyNormals == 2 && gs.n == 2) { + c.type = SAME_ORIENTATION; + c.entityA = gs.anyNormal[0]; + c.entityB = gs.anyNormal[1]; + } else { + Error("Bad selection for same orientation constraint."); + return; + } + AddConstraint(&c); + break; + + case GraphicsWindow::MNU_PARALLEL: + if(gs.vectors == 2 && gs.n == 2) { + c.type = PARALLEL; + c.entityA = gs.vector[0]; + c.entityB = gs.vector[1]; + } else { + Error("Bad selection for parallel constraint."); + return; + } + AddConstraint(&c); + break; + case GraphicsWindow::MNU_SOLVE_NOW: SS.GenerateAll(true); return; @@ -528,6 +552,37 @@ void Constraint::Generate(IdList *l) { break; } + case SAME_ORIENTATION: { + Entity *a = SS.GetEntity(entityA); + Entity *b = SS.GetEntity(entityB); + ExprVector au = a->NormalExprsU(), + av = a->NormalExprsV(), + an = a->NormalExprsN(); + ExprVector bu = b->NormalExprsU(), + bv = b->NormalExprsV(), + bn = b->NormalExprsN(); + + AddEq(l, VectorsParallel(0, an, bn), 0); + AddEq(l, VectorsParallel(1, an, bn), 1); + AddEq(l, au.Dot(bv), 2); + break; + } + + case PARALLEL: { + ExprVector a = SS.GetEntity(entityA)->VectorGetExprs(); + ExprVector b = SS.GetEntity(entityB)->VectorGetExprs(); + + if(workplane.v == Entity::FREE_IN_3D.v) { + AddEq(l, VectorsParallel(0, a, b), 0); + AddEq(l, VectorsParallel(1, a, b), 1); + } else { + Entity *w = SS.GetEntity(workplane); + ExprVector wn = w->Normal()->NormalExprsN(); + AddEq(l, (a.Cross(b)).Dot(wn), 0); + } + break; + } + default: oops(); } } diff --git a/drawconstraint.cpp b/drawconstraint.cpp index 0782724..849e29d 100644 --- a/drawconstraint.cpp +++ b/drawconstraint.cpp @@ -231,6 +231,35 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) { break; } + case SAME_ORIENTATION: { + for(int i = 0; i < 2; i++) { + Entity *e = SS.GetEntity(i == 0 ? entityA : entityB); + Quaternion q = e->NormalGetNum(); + Vector n = q.RotationN().WithMagnitude(25/SS.GW.scale); + Vector u = q.RotationU().WithMagnitude(6/SS.GW.scale); + Vector p = SS.GetEntity(e->point[0])->PointGetNum(); + p = p.Plus(n.WithMagnitude(10/SS.GW.scale)); + + LineDrawOrGetDistance(p.Plus(u), p.Minus(u).Plus(n)); + LineDrawOrGetDistance(p.Minus(u), p.Plus(u).Plus(n)); + } + break; + } + + case PARALLEL: { + for(int i = 0; i < 2; i++) { + Entity *e = SS.GetEntity(i == 0 ? entityA : entityB); + Vector n = e->VectorGetExprs().Eval(); + n = n.WithMagnitude(25/SS.GW.scale); + Vector u = (gn.Cross(n)).WithMagnitude(4/SS.GW.scale); + Vector p = e->VectorGetRefPoint(); + + LineDrawOrGetDistance(p.Plus(u), p.Plus(u).Plus(n)); + LineDrawOrGetDistance(p.Minus(u), p.Minus(u).Plus(n)); + } + break; + } + case EQUAL_LENGTH_LINES: { for(int i = 0; i < 2; i++) { Entity *e = SS.GetEntity(i == 0 ? entityA : entityB); diff --git a/entity.cpp b/entity.cpp index bcb36b4..447fd9f 100644 --- a/entity.cpp +++ b/entity.cpp @@ -5,6 +5,49 @@ char *Entity::DescriptionString(void) { return r->DescriptionString(); } +bool Entity::HasVector(void) { + switch(type) { + case LINE_SEGMENT: + case NORMAL_IN_3D: + case NORMAL_IN_2D: + case NORMAL_XFRMD: + return true; + + default: + return false; + } +} + +ExprVector Entity::VectorGetExprs(void) { + switch(type) { + case LINE_SEGMENT: + return (SS.GetEntity(point[0])->PointGetExprs()).Minus( + SS.GetEntity(point[1])->PointGetExprs()); + + case NORMAL_IN_3D: + case NORMAL_IN_2D: + case NORMAL_XFRMD: + return NormalExprsN(); + + default: oops(); + } +} + +Vector Entity::VectorGetRefPoint(void) { + switch(type) { + case LINE_SEGMENT: + return ((SS.GetEntity(point[0])->PointGetNum()).Plus( + SS.GetEntity(point[1])->PointGetNum())).ScaledBy(0.5); + + case NORMAL_IN_3D: + case NORMAL_IN_2D: + case NORMAL_XFRMD: + return SS.GetEntity(point[0])->PointGetNum(); + + default: oops(); + } +} + bool Entity::IsCircle(void) { return (type == CIRCLE); } @@ -456,10 +499,13 @@ void Entity::DrawOrGetDistance(int order) { Vector mp = p.Minus(us).Plus (vs); glxColor3d(0, 0.3, 0.3); + glEnable(GL_LINE_STIPPLE); + glLineStipple(3, 0x1111); LineDrawOrGetDistance(pp, pm); LineDrawOrGetDistance(pm, mm); LineDrawOrGetDistance(mm, mp); LineDrawOrGetDistance(mp, pp); + glDisable(GL_LINE_STIPPLE); if(dogd.drawing) { glPushMatrix(); diff --git a/expr.cpp b/expr.cpp index fd9b284..dc3f827 100644 --- a/expr.cpp +++ b/expr.cpp @@ -53,6 +53,14 @@ Expr *ExprVector::Magnitude(void) { return r->Sqrt(); } +Vector ExprVector::Eval(void) { + Vector r; + r.x = x->Eval(); + r.y = y->Eval(); + r.z = z->Eval(); + return r; +} + ExprQuaternion ExprQuaternion::FromExprs(Expr *w, Expr *vx, Expr *vy, Expr *vz) { ExprQuaternion q; diff --git a/expr.h b/expr.h index b84e260..b55ca48 100644 --- a/expr.h +++ b/expr.h @@ -130,6 +130,8 @@ public: ExprVector Cross(ExprVector b); ExprVector ScaledBy(Expr *s); Expr *Magnitude(void); + + Vector Eval(void); }; class ExprQuaternion { diff --git a/graphicswin.cpp b/graphicswin.cpp index cdb66ba..0261940 100644 --- a/graphicswin.cpp +++ b/graphicswin.cpp @@ -79,6 +79,8 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = { { 1, "E&qual Length / Radius\tShift+Q", MNU_EQUAL, 'Q'|S, mCon }, { 1, "At &Midpoint\tShift+M", MNU_AT_MIDPOINT, 'M'|S, mCon }, { 1, "S&ymmetric\tShift+Y", MNU_SYMMETRIC, 'Y'|S, mCon }, +{ 1, "Para&llel\tShift+L", MNU_PARALLEL, 'L'|S, mCon }, +{ 1, "Same O&rientation\tShift+R", MNU_ORIENTED_SAME, 'R'|S, mCon }, { 1, NULL, 0, NULL }, { 1, "Sym&bolic Equation\tShift+B", 0, 'B'|S, NULL }, { 1, NULL, 0, NULL }, @@ -627,11 +629,27 @@ void GraphicsWindow::GroupSelection(void) { (gs.n)++; Entity *e = SS.entity.FindById(s->entity); + // A list of points, and a list of all entities that aren't points. if(e->IsPoint()) { gs.point[(gs.points)++] = s->entity; } else { gs.entity[(gs.entities)++] = s->entity; } + + // And an auxiliary list of normals, including normals from + // workplanes. + if(e->IsNormal()) { + gs.anyNormal[(gs.anyNormals)++] = s->entity; + } else if(e->IsWorkplane()) { + gs.anyNormal[(gs.anyNormals)++] = e->Normal()->h; + } + + // And of vectors (i.e., stuff with a direction to constrain) + if(e->HasVector()) { + gs.vector[(gs.vectors)++] = s->entity; + } + + // And some aux counts too switch(e->type) { case Entity::WORKPLANE: (gs.workplanes)++; break; case Entity::LINE_SEGMENT: (gs.lineSegments)++; break; diff --git a/sketch.h b/sketch.h index 5acc9d8..f14c7f1 100644 --- a/sketch.h +++ b/sketch.h @@ -205,8 +205,9 @@ public: bool IsCircle(void); - bool HasDirection(void); - ExprVector GetDirection(void); + bool HasVector(void); + ExprVector VectorGetExprs(void); + Vector VectorGetRefPoint(void); // For distances double DistanceGetNum(void); @@ -300,6 +301,8 @@ public: static const int VERTICAL = 81; static const int DIAMETER = 90; static const int PT_ON_CIRCLE = 100; + static const int SAME_ORIENTATION = 110; + static const int PARALLEL = 120; int tag; hConstraint h; diff --git a/system.cpp b/system.cpp index e6fa9ea..e2db3e4 100644 --- a/system.cpp +++ b/system.cpp @@ -81,6 +81,20 @@ bool System::IsDragged(hParam p) { } } } + if(SS.GW.pending.normal.v) { + Entity *norm = SS.entity.FindByIdNoOops(SS.GW.pending.normal); + if(norm) { + switch(norm->type) { + case Entity::NORMAL_IN_3D: + if(p.v == (norm->param[0].v)) return true; + if(p.v == (norm->param[1].v)) return true; + if(p.v == (norm->param[2].v)) return true; + if(p.v == (norm->param[3].v)) return true; + break; + // other types are locked, so not draggable + } + } + } return false; } diff --git a/ui.h b/ui.h index b0ce66c..ffc4787 100644 --- a/ui.h +++ b/ui.h @@ -119,6 +119,8 @@ public: MNU_AT_MIDPOINT, MNU_HORIZONTAL, MNU_VERTICAL, + MNU_PARALLEL, + MNU_ORIENTED_SAME, MNU_SOLVE_AUTO, MNU_SOLVE_NOW, } MenuId; @@ -219,11 +221,15 @@ public: struct { hEntity point[MAX_SELECTED]; hEntity entity[MAX_SELECTED]; + hEntity anyNormal[MAX_SELECTED]; + hEntity vector[MAX_SELECTED]; int points; int entities; int workplanes; int lineSegments; int circlesOrArcs; + int anyNormals; + int vectors; int n; } gs; void GroupSelection(void);