From 48c501861346e45c1925aa56d17dfbe20b45de9b Mon Sep 17 00:00:00 2001 From: Jonathan Westhues Date: Tue, 1 Jul 2008 22:59:49 -0800 Subject: [PATCH] Add symmetric about line constraint. This applies only when locked in a workplane, since it would otherwise be ambiguous. [git-p4: depot-paths = "//depot/solvespace/": change = 1817] --- constraint.cpp | 64 ++++++++++++++++++++++++++++++++++++++++++++-- drawconstraint.cpp | 12 +++++++++ sketch.h | 1 + textscreens.cpp | 5 ++-- wishlist.txt | 2 +- 5 files changed, 79 insertions(+), 5 deletions(-) diff --git a/constraint.cpp b/constraint.cpp index 5527295..22252fa 100644 --- a/constraint.cpp +++ b/constraint.cpp @@ -22,6 +22,7 @@ char *Constraint::DescriptionString(void) { case SYMMETRIC: s = "symmetric"; break; case SYMMETRIC_HORIZ: s = "symmetric-h"; break; case SYMMETRIC_VERT: s = "symmetric-v"; break; + case SYMMETRIC_LINE: s = "symmetric-line"; break; case AT_MIDPOINT: s = "at-midpoint"; break; case HORIZONTAL: s = "horizontal"; break; case VERTICAL: s = "vertical"; break; @@ -70,7 +71,7 @@ void Constraint::ConstrainCoincident(hEntity ptA, hEntity ptB) { void Constraint::MenuConstrain(int id) { Constraint c; - memset(&c, 0, sizeof(c)); + ZERO(&c); c.group = SS.GW.activeGroup; c.workplane = SS.GW.ActiveWorkplane(); @@ -235,11 +236,37 @@ void Constraint::MenuConstrain(int id) { c.entityA = gs.entity[1-i]; c.ptA = line->point[0]; c.ptB = line->point[1]; + } else if(SS.GW.LockedInWorkplane() + && gs.lineSegments == 2 && gs.n == 2) + { + Entity *l0 = SS.GetEntity(gs.entity[0]), + *l1 = SS.GetEntity(gs.entity[1]); + + if((l1->group.v != SS.GW.activeGroup.v) || + (l1->construction && !(l0->construction))) + { + SWAP(Entity *, l0, l1); + } + c.ptA = l1->point[0]; + c.ptB = l1->point[1]; + c.entityA = l0->h; + c.type = SYMMETRIC_LINE; + } else if(SS.GW.LockedInWorkplane() + && gs.lineSegments == 1 && gs.points == 2 && gs.n == 3) + { + c.ptA = gs.point[0]; + c.ptB = gs.point[1]; + c.entityA = gs.entity[0]; + c.type = SYMMETRIC_LINE; } else { Error("Bad selection for symmetric constraint."); return; } - if(c.entityA.v == Entity::NO_ENTITY.v) { + if(c.type != 0) { + // Already done, symmetry about a line segment in a workplane + } else if(c.entityA.v == Entity::NO_ENTITY.v) { + // Horizontal / vertical symmetry, implicit symmetry plane + // normal to the workplane if(c.workplane.v == Entity::FREE_IN_3D.v) { Error("Must be locked in to workplane when constraining " "symmetric without an explicit symmetry plane."); @@ -832,6 +859,39 @@ void Constraint::GenerateReal(IdList *l) { break; } + case SYMMETRIC_LINE: { + Entity *pa = SS.GetEntity(ptA); + Entity *pb = SS.GetEntity(ptB); + + Expr *pau, *pav, *pbu, *pbv; + pa->PointGetExprsInWorkplane(workplane, &pau, &pav); + pb->PointGetExprsInWorkplane(workplane, &pbu, &pbv); + + Entity *ln = SS.GetEntity(entityA); + Entity *la = SS.GetEntity(ln->point[0]); + Entity *lb = SS.GetEntity(ln->point[1]); + Expr *lau, *lav, *lbu, *lbv; + la->PointGetExprsInWorkplane(workplane, &lau, &lav); + lb->PointGetExprsInWorkplane(workplane, &lbu, &lbv); + + Expr *dpu = pbu->Minus(pau), *dpv = pbv->Minus(pav); + Expr *dlu = lbu->Minus(lau), *dlv = lbv->Minus(lav); + + // The line through the points is perpendicular to the line + // of symmetry. + AddEq(l, (dlu->Times(dpu))->Plus(dlv->Times(dpv)), 0); + + // And the signed distances of the points to the line are + // equal in magnitude and opposite in sign, so sum to zero + Expr *dista = (dlv->Times(lau->Minus(pau)))->Minus( + (dlu->Times(lav->Minus(pav)))); + Expr *distb = (dlv->Times(lau->Minus(pbu)))->Minus( + (dlu->Times(lav->Minus(pbv)))); + AddEq(l, dista->Plus(distb), 1); + + break; + } + case HORIZONTAL: case VERTICAL: { hEntity ha, hb; diff --git a/drawconstraint.cpp b/drawconstraint.cpp index ef04ef8..3d40e19 100644 --- a/drawconstraint.cpp +++ b/drawconstraint.cpp @@ -491,9 +491,21 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) { n = SS.GetEntity(workplane)->Normal()->NormalU(); goto s; case SYMMETRIC_VERT: n = SS.GetEntity(workplane)->Normal()->NormalV(); goto s; + case SYMMETRIC_LINE: { + Entity *ln = SS.GetEntity(entityA); + Vector la = SS.GetEntity(ln->point[0])->PointGetNum(), + lb = SS.GetEntity(ln->point[1])->PointGetNum(); + la = la.ProjectInto(workplane); + lb = lb.ProjectInto(workplane); + n = lb.Minus(la); + Vector nw = SS.GetEntity(workplane)->Normal()->NormalN(); + n = n.RotatedAbout(nw, PI/2); + goto s; + } s: Vector a = SS.GetEntity(ptA)->PointGetNum(); Vector b = SS.GetEntity(ptB)->PointGetNum(); + for(int i = 0; i < 2; i++) { Vector tail = (i == 0) ? a : b; Vector d = (i == 0) ? b : a; diff --git a/sketch.h b/sketch.h index 80e1964..22f453d 100644 --- a/sketch.h +++ b/sketch.h @@ -447,6 +447,7 @@ public: static const int SYMMETRIC = 60; static const int SYMMETRIC_HORIZ = 61; static const int SYMMETRIC_VERT = 62; + static const int SYMMETRIC_LINE = 63; static const int AT_MIDPOINT = 70; static const int HORIZONTAL = 80; static const int VERTICAL = 81; diff --git a/textscreens.cpp b/textscreens.cpp index 5dcfa7c..6dcf836 100644 --- a/textscreens.cpp +++ b/textscreens.cpp @@ -463,10 +463,11 @@ void TextWindow::ShowGroupInfo(void) { if(c->group.v == shown->group.v) { char *s = c->DescriptionString(); - Printf(false, "%Bp %Fl%Ll%D%f%h%s%E", + Printf(false, "%Bp %Fl%Ll%D%f%h%s%E %s", (a & 1) ? 'd' : 'a', c->h.v, (&TextWindow::ScreenSelectConstraint), - (&TextWindow::ScreenHoverConstraint), s); + (&TextWindow::ScreenHoverConstraint), s, + c->reference ? "(ref)" : ""); a++; } } diff --git a/wishlist.txt b/wishlist.txt index e0ca871..1bcac2b 100644 --- a/wishlist.txt +++ b/wishlist.txt @@ -8,7 +8,7 @@ auto-generate circles and faces when lathing copy the section geometry to other end when sweeping cylindrical faces draw explicit edges -symmetric about line segment +perpendicular constraint long term