Add angle constraints. I'm doing these differently from SketchFlat,
as a constraint on the direction cosine, rather than driving the dot product against a rotated vector to zero. The drawing is the ugly part; to do that for skew lines, I gave up. Also add a function to clear non-existent items on the selection after solving, since that could have caused an oops(). [git-p4: depot-paths = "//depot/solvespace/": change = 1727]solver
parent
749e2a0149
commit
b480613763
108
constraint.cpp
108
constraint.cpp
|
@ -237,6 +237,33 @@ void Constraint::MenuConstrain(int id) {
|
|||
AddConstraint(&c);
|
||||
break;
|
||||
|
||||
case GraphicsWindow::MNU_OTHER_ANGLE:
|
||||
if(gs.constraints == 1 && gs.n == 0) {
|
||||
Constraint *c = SS.GetConstraint(gs.constraint[0]);
|
||||
if(c->type == ANGLE) {
|
||||
c->otherAngle = !(c->otherAngle);
|
||||
c->ModifyToSatisfy();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Error("Must select an angle constraint.");
|
||||
break;
|
||||
|
||||
case GraphicsWindow::MNU_ANGLE:
|
||||
if(gs.vectors == 2 && gs.n == 2) {
|
||||
c.type = ANGLE;
|
||||
c.entityA = gs.vector[0];
|
||||
c.entityB = gs.vector[1];
|
||||
c.exprA = Expr::FromConstant(0)->DeepCopyKeep();
|
||||
c.otherAngle = true;
|
||||
} else {
|
||||
Error("Bad selection for angle constraint.");
|
||||
return;
|
||||
}
|
||||
c.ModifyToSatisfy();
|
||||
AddConstraint(&c);
|
||||
break;
|
||||
|
||||
case GraphicsWindow::MNU_PARALLEL:
|
||||
if(gs.vectors == 2 && gs.n == 2) {
|
||||
c.type = PARALLEL;
|
||||
|
@ -374,21 +401,37 @@ ExprVector Constraint::PointInThreeSpace(hEntity workplane, Expr *u, Expr *v) {
|
|||
}
|
||||
|
||||
void Constraint::ModifyToSatisfy(void) {
|
||||
IdList<Equation,hEquation> l;
|
||||
// An uninit IdList could lead us to free some random address, bad.
|
||||
memset(&l, 0, sizeof(l));
|
||||
if(type == ANGLE) {
|
||||
Vector a = SS.GetEntity(entityA)->VectorGetNum();
|
||||
Vector b = SS.GetEntity(entityB)->VectorGetNum();
|
||||
if(otherAngle) a = a.ScaledBy(-1);
|
||||
if(workplane.v != Entity::FREE_IN_3D.v) {
|
||||
a = a.ProjectVectorInto(workplane);
|
||||
b = b.ProjectVectorInto(workplane);
|
||||
}
|
||||
double c = (a.Dot(b))/(a.Magnitude() * b.Magnitude());
|
||||
double theta = acos(c)*180/PI;
|
||||
Expr::FreeKeep(&exprA);
|
||||
exprA = Expr::FromConstant(theta)->DeepCopyKeep();
|
||||
} else {
|
||||
// We'll fix these ones up by looking at their symbolic equation;
|
||||
// that means no extra work.
|
||||
IdList<Equation,hEquation> l;
|
||||
// An uninit IdList could lead us to free some random address, bad.
|
||||
memset(&l, 0, sizeof(l));
|
||||
|
||||
Generate(&l);
|
||||
if(l.n != 1) oops();
|
||||
Generate(&l);
|
||||
if(l.n != 1) oops();
|
||||
|
||||
// These equations are written in the form f(...) - d = 0, where
|
||||
// d is the value of the exprA.
|
||||
double v = (l.elem[0].e)->Eval();
|
||||
double nd = exprA->Eval() + v;
|
||||
Expr::FreeKeep(&exprA);
|
||||
exprA = Expr::FromConstant(nd)->DeepCopyKeep();
|
||||
// These equations are written in the form f(...) - d = 0, where
|
||||
// d is the value of the exprA.
|
||||
double v = (l.elem[0].e)->Eval();
|
||||
double nd = exprA->Eval() + v;
|
||||
Expr::FreeKeep(&exprA);
|
||||
exprA = Expr::FromConstant(nd)->DeepCopyKeep();
|
||||
|
||||
l.Clear();
|
||||
l.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
void Constraint::AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index) {
|
||||
|
@ -399,19 +442,22 @@ void Constraint::AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index) {
|
|||
}
|
||||
|
||||
void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
||||
Expr *exA = NULL;
|
||||
if(exprA) exA = exprA->DeepCopy();
|
||||
|
||||
switch(type) {
|
||||
case PT_PT_DISTANCE:
|
||||
AddEq(l, Distance(workplane, ptA, ptB)->Minus(exprA), 0);
|
||||
AddEq(l, Distance(workplane, ptA, ptB)->Minus(exA), 0);
|
||||
break;
|
||||
|
||||
case PT_LINE_DISTANCE:
|
||||
AddEq(l,
|
||||
PointLineDistance(workplane, ptA, entityA)->Minus(exprA), 0);
|
||||
PointLineDistance(workplane, ptA, entityA)->Minus(exA), 0);
|
||||
break;
|
||||
|
||||
case PT_PLANE_DISTANCE: {
|
||||
ExprVector pt = SS.GetEntity(ptA)->PointGetExprs();
|
||||
AddEq(l, (PointPlaneDistance(pt, entityA))->Minus(exprA), 0);
|
||||
AddEq(l, (PointPlaneDistance(pt, entityA))->Minus(exA), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -428,14 +474,14 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
|||
Entity *b = SS.GetEntity(entityB);
|
||||
Expr *la = Distance(workplane, a->point[0], a->point[1]);
|
||||
Expr *lb = Distance(workplane, b->point[0], b->point[1]);
|
||||
AddEq(l, (la->Div(lb))->Minus(exprA), 0);
|
||||
AddEq(l, (la->Div(lb))->Minus(exA), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case DIAMETER: {
|
||||
Entity *circle = SS.GetEntity(entityA);
|
||||
Expr *r = circle->CircleGetRadiusExpr();
|
||||
AddEq(l, (r->Times(Expr::FromConstant(2)))->Minus(exprA), 0);
|
||||
AddEq(l, (r->Times(Expr::FromConstant(2)))->Minus(exA), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -656,6 +702,34 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
|||
break;
|
||||
}
|
||||
|
||||
case ANGLE: {
|
||||
Entity *a = SS.GetEntity(entityA);
|
||||
Entity *b = SS.GetEntity(entityB);
|
||||
ExprVector ae = a->VectorGetExprs();
|
||||
ExprVector be = b->VectorGetExprs();
|
||||
if(otherAngle) ae = ae.ScaledBy(Expr::FromConstant(-1));
|
||||
Expr *c;
|
||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||
Expr *mags = (ae.Magnitude())->Times(be.Magnitude());
|
||||
c = (ae.Dot(be))->Div(mags);
|
||||
} else {
|
||||
Entity *w = SS.GetEntity(workplane);
|
||||
ExprVector u = w->Normal()->NormalExprsU();
|
||||
ExprVector v = w->Normal()->NormalExprsV();
|
||||
Expr *ua = u.Dot(ae);
|
||||
Expr *va = v.Dot(ae);
|
||||
Expr *ub = u.Dot(be);
|
||||
Expr *vb = v.Dot(be);
|
||||
Expr *maga = (ua->Square()->Plus(va->Square()))->Sqrt();
|
||||
Expr *magb = (ub->Square()->Plus(vb->Square()))->Sqrt();
|
||||
Expr *dot = (ua->Times(ub))->Plus(va->Times(vb));
|
||||
c = dot->Div(maga->Times(magb));
|
||||
}
|
||||
Expr *rads = exA->Times(Expr::FromConstant(PI/180));
|
||||
AddEq(l, c->Minus(rads->Cos()), 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case PARALLEL: {
|
||||
ExprVector a = SS.GetEntity(entityA)->VectorGetExprs();
|
||||
ExprVector b = SS.GetEntity(entityB)->VectorGetExprs();
|
||||
|
|
|
@ -7,6 +7,7 @@ bool Constraint::HasLabel(void) {
|
|||
case PT_PT_DISTANCE:
|
||||
case DIAMETER:
|
||||
case LENGTH_RATIO:
|
||||
case ANGLE:
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
@ -247,6 +248,83 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
break;
|
||||
}
|
||||
|
||||
case ANGLE: {
|
||||
Entity *a = SS.GetEntity(entityA);
|
||||
Entity *b = SS.GetEntity(entityB);
|
||||
|
||||
Vector a0 = a->VectorGetRefPoint();
|
||||
Vector b0 = b->VectorGetRefPoint();
|
||||
Vector da = a->VectorGetNum();
|
||||
Vector db = b->VectorGetNum();
|
||||
if(otherAngle) da = da.ScaledBy(-1);
|
||||
|
||||
if(workplane.v != Entity::FREE_IN_3D.v) {
|
||||
a0 = a0.ProjectInto(workplane);
|
||||
b0 = b0.ProjectInto(workplane);
|
||||
da = da.ProjectVectorInto(workplane);
|
||||
db = db.ProjectVectorInto(workplane);
|
||||
}
|
||||
|
||||
// Make an orthogonal coordinate system from those directions
|
||||
Vector dn = da.Cross(db); // normal to both
|
||||
Vector dna = dn.Cross(da); // normal to da
|
||||
Vector dnb = dn.Cross(db); // normal to db
|
||||
// At the intersection of the lines
|
||||
// a0 + pa*da = b0 + pb*db (where pa, pb are scalar params)
|
||||
// So dot this equation against dna and dnb to get two equations
|
||||
// to solve for da and db
|
||||
double pb = ((a0.Minus(b0)).Dot(dna))/(db.Dot(dna));
|
||||
double pa = -((a0.Minus(b0)).Dot(dnb))/(da.Dot(dnb));
|
||||
|
||||
Vector pi = a0.Plus(da.ScaledBy(pa));
|
||||
Vector ref;
|
||||
if(pi.Equals(b0.Plus(db.ScaledBy(pb)))) {
|
||||
ref = pi.Plus(disp.offset);
|
||||
// We draw in a coordinate system centered at pi, with
|
||||
// basis vectors da and dna.
|
||||
da = da.WithMagnitude(1); dna = dna.WithMagnitude(1);
|
||||
Vector rm = ref.Minus(pi);
|
||||
double rda = rm.Dot(da), rdna = rm.Dot(dna);
|
||||
double r = sqrt(rda*rda + rdna*rdna);
|
||||
double c = (da.Dot(db))/(da.Magnitude()*db.Magnitude());
|
||||
double thetaf = acos(c);
|
||||
|
||||
Vector m = da.ScaledBy(cos(thetaf/2)).Plus(
|
||||
dna.ScaledBy(sin(thetaf/2)));
|
||||
if(m.Dot(rm) < 0) {
|
||||
da = da.ScaledBy(-1); dna = dna.ScaledBy(-1);
|
||||
}
|
||||
|
||||
Vector prev = da.ScaledBy(r).Plus(pi);
|
||||
int i, n = 30;
|
||||
for(i = 0; i <= n; i++) {
|
||||
double theta = (i*thetaf)/n;
|
||||
Vector p = da. ScaledBy(r*cos(theta)).Plus(
|
||||
dna.ScaledBy(r*sin(theta))).Plus(pi);
|
||||
LineDrawOrGetDistance(prev, p);
|
||||
prev = p;
|
||||
}
|
||||
|
||||
double tl = atan2(rm.Dot(gu), rm.Dot(gr));
|
||||
double adj = EllipticalInterpolation(
|
||||
glxStrWidth(exprA->Print())/2, glxStrHeight()/2, tl);
|
||||
ref = ref.Plus(rm.WithMagnitude(adj + 3/SS.GW.scale));
|
||||
} else {
|
||||
// The lines are skew; no wonderful way to illustrate that.
|
||||
ref = a->VectorGetRefPoint().Plus(b->VectorGetRefPoint());
|
||||
ref = ref.ScaledBy(0.5).Plus(disp.offset);
|
||||
glPushMatrix();
|
||||
gu = gu.WithMagnitude(1);
|
||||
glxTranslatev(ref.Plus(gu.ScaledBy(-1.5*glxStrHeight())));
|
||||
glxOntoWorkplane(gr, gu);
|
||||
glxWriteTextRefCenter("angle between skew lines");
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
DoLabel(ref, labelPos, gr, gu);
|
||||
break;
|
||||
}
|
||||
|
||||
case PARALLEL: {
|
||||
for(int i = 0; i < 2; i++) {
|
||||
Entity *e = SS.GetEntity(i == 0 ? entityA : entityB);
|
||||
|
|
1
dsc.h
1
dsc.h
|
@ -53,6 +53,7 @@ public:
|
|||
Vector WithMagnitude(double s);
|
||||
Vector ScaledBy(double s);
|
||||
Vector ProjectInto(hEntity wrkpl);
|
||||
Vector ProjectVectorInto(hEntity wrkpl);
|
||||
double DivPivoting(Vector delta);
|
||||
Vector ClosestOrtho(void);
|
||||
Point2d Project2d(Vector u, Vector v);
|
||||
|
|
1
file.cpp
1
file.cpp
|
@ -112,6 +112,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
|
|||
{ 'c', "Constraint.ptC.v", 'x', &(SS.sv.c.ptC.v) },
|
||||
{ 'c', "Constraint.entityA.v", 'x', &(SS.sv.c.entityA.v) },
|
||||
{ 'c', "Constraint.entityB.v", 'x', &(SS.sv.c.entityB.v) },
|
||||
{ 'c', "Constraint.otherAngle", 'b', &(SS.sv.c.otherAngle) },
|
||||
{ 'c', "Constraint.disp.offset.x", 'f', &(SS.sv.c.disp.offset.x) },
|
||||
{ 'c', "Constraint.disp.offset.y", 'f', &(SS.sv.c.disp.offset.y) },
|
||||
{ 'c', "Constraint.disp.offset.z", 'f', &(SS.sv.c.disp.offset.z) },
|
||||
|
|
|
@ -70,8 +70,8 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||
|
||||
{ 0, "&Constrain", 0, NULL },
|
||||
{ 1, "&Distance / Diameter\tShift+D", MNU_DISTANCE_DIA, 'D'|S, mCon },
|
||||
{ 1, "A&ngle\tShift+N", 0, 'N'|S, NULL },
|
||||
{ 1, "Other S&upplementary Angle\tShift+U", 0, 'U'|S, NULL },
|
||||
{ 1, "A&ngle\tShift+N", MNU_ANGLE, 'N'|S, mCon },
|
||||
{ 1, "Other S&upplementary Angle\tShift+U", MNU_OTHER_ANGLE, 'U'|S, mCon },
|
||||
{ 1, NULL, 0, NULL },
|
||||
{ 1, "&Horizontal\tShift+H", MNU_HORIZONTAL, 'H'|S, mCon },
|
||||
{ 1, "&Vertical\tShift+V", MNU_VERTICAL, 'V'|S, mCon },
|
||||
|
@ -302,8 +302,7 @@ void GraphicsWindow::MenuEdit(int id) {
|
|||
SS.constraint.RemoveTagged();
|
||||
|
||||
// Forget any mention of the just-deleted entity
|
||||
SS.GW.ClearSelection();
|
||||
SS.GW.hover.Clear();
|
||||
SS.GW.ClearSuper();
|
||||
// And regenerate to get rid of what it generates, plus anything
|
||||
// that references it (since the regen code checks for that).
|
||||
SS.GW.GeneratePerSolving();
|
||||
|
@ -633,6 +632,13 @@ void GraphicsWindow::Selection::Draw(void) {
|
|||
if(constraint.v) SS.GetConstraint(constraint)->Draw();
|
||||
}
|
||||
|
||||
void GraphicsWindow::ClearSuper(void) {
|
||||
ClearPending();
|
||||
ClearSelection();
|
||||
hover.Clear();
|
||||
EnsureValidActives();
|
||||
}
|
||||
|
||||
void GraphicsWindow::ClearPending(void) {
|
||||
memset(&pending, 0, sizeof(pending));
|
||||
}
|
||||
|
@ -680,6 +686,22 @@ void GraphicsWindow::ClearSelection(void) {
|
|||
InvalidateGraphics();
|
||||
}
|
||||
|
||||
void GraphicsWindow::ClearNonexistentSelectionItems(void) {
|
||||
bool change = false;
|
||||
for(int i = 0; i < MAX_SELECTED; i++) {
|
||||
Selection *s = &(selection[i]);
|
||||
if(s->constraint.v && !(SS.constraint.FindByIdNoOops(s->constraint))) {
|
||||
s->constraint.v = 0;
|
||||
change = true;
|
||||
}
|
||||
if(s->entity.v && !(SS.entity.FindByIdNoOops(s->entity))) {
|
||||
s->entity.v = 0;
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
if(change) InvalidateGraphics();
|
||||
}
|
||||
|
||||
void GraphicsWindow::GroupSelection(void) {
|
||||
memset(&gs, 0, sizeof(gs));
|
||||
int i;
|
||||
|
@ -718,6 +740,9 @@ void GraphicsWindow::GroupSelection(void) {
|
|||
case Entity::CIRCLE: (gs.circlesOrArcs)++; break;
|
||||
}
|
||||
}
|
||||
if(s->constraint.v) {
|
||||
gs.constraint[(gs.constraints)++] = s->constraint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -794,7 +819,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
hr = AddRequest(Request::DATUM_POINT);
|
||||
SS.GetEntity(hr.entity(0))->PointForceTo(v);
|
||||
|
||||
ClearSelection(); hover.Clear();
|
||||
ClearSuper();
|
||||
|
||||
pending.operation = 0;
|
||||
break;
|
||||
|
@ -804,7 +829,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
||||
ConstrainPointByHovered(hr.entity(1));
|
||||
|
||||
ClearSelection(); hover.Clear();
|
||||
ClearSuper();
|
||||
|
||||
pending.operation = DRAGGING_NEW_LINE_POINT;
|
||||
pending.point = hr.entity(2);
|
||||
|
@ -848,9 +873,8 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp));
|
||||
ConstrainPointByHovered(hr.entity(1));
|
||||
|
||||
ClearSelection(); hover.Clear();
|
||||
ClearSuper();
|
||||
|
||||
ClearPending();
|
||||
pending.operation = DRAGGING_NEW_RADIUS;
|
||||
pending.circle = hr.entity(0);
|
||||
pending.description = "click to set radius";
|
||||
|
@ -869,9 +893,8 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
SS.GetEntity(hr.entity(3))->PointForceTo(v);
|
||||
ConstrainPointByHovered(hr.entity(2));
|
||||
|
||||
ClearSelection(); hover.Clear();
|
||||
ClearSuper();
|
||||
|
||||
ClearPending();
|
||||
pending.operation = DRAGGING_NEW_ARC_POINT;
|
||||
pending.point = hr.entity(3);
|
||||
pending.description = "click to place point";
|
||||
|
@ -885,7 +908,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
SS.GetEntity(hr.entity(4))->PointForceTo(v);
|
||||
ConstrainPointByHovered(hr.entity(1));
|
||||
|
||||
ClearSelection(); hover.Clear();
|
||||
ClearSuper();
|
||||
|
||||
pending.operation = DRAGGING_NEW_CUBIC_POINT;
|
||||
pending.point = hr.entity(4);
|
||||
|
@ -899,8 +922,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
|||
Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp));
|
||||
ConstrainPointByHovered(hr.entity(1));
|
||||
|
||||
ClearSelection(); hover.Clear();
|
||||
ClearPending();
|
||||
ClearSuper();
|
||||
break;
|
||||
|
||||
case DRAGGING_RADIUS:
|
||||
|
@ -986,12 +1008,13 @@ void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
|
|||
if(GraphicsEditControlIsVisible()) return;
|
||||
|
||||
if(hover.constraint.v) {
|
||||
ClearSelection();
|
||||
Constraint *c = SS.GetConstraint(hover.constraint);
|
||||
Vector p3 = c->GetLabelPos();
|
||||
Point2d p2 = ProjectPoint(p3);
|
||||
ShowGraphicsEditControl((int)p2.x, (int)p2.y, c->exprA->Print());
|
||||
constraintBeingEdited = hover.constraint;
|
||||
|
||||
ClearSuper();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -497,7 +497,9 @@ void Group::Draw(void) {
|
|||
int i;
|
||||
glEnable(GL_LIGHTING);
|
||||
GLfloat vec[] = { 0.3f, 0.3f, 0.3f, 1.0 };
|
||||
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, vec);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, vec);
|
||||
GLfloat vec2[] = { 1.0f, 0.3f, 0.3f, 1.0 };
|
||||
glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, vec2);
|
||||
for(i = 0; i < faces.n; i++) {
|
||||
glxFillPolygon(&(faces.elem[i]));
|
||||
#if 0
|
||||
|
|
4
sketch.h
4
sketch.h
|
@ -343,7 +343,8 @@ public:
|
|||
static const int DIAMETER = 90;
|
||||
static const int PT_ON_CIRCLE = 100;
|
||||
static const int SAME_ORIENTATION = 110;
|
||||
static const int PARALLEL = 120;
|
||||
static const int ANGLE = 120;
|
||||
static const int PARALLEL = 121;
|
||||
static const int EQUAL_RADIUS = 130;
|
||||
|
||||
int tag;
|
||||
|
@ -362,6 +363,7 @@ public:
|
|||
hEntity ptC;
|
||||
hEntity entityA;
|
||||
hEntity entityB;
|
||||
bool otherAngle;
|
||||
|
||||
// These define how the constraint is drawn on-screen.
|
||||
struct {
|
||||
|
|
|
@ -184,6 +184,10 @@ void SolveSpace::GenerateAll(bool andSolve) {
|
|||
prev.Clear();
|
||||
InvalidateGraphics();
|
||||
|
||||
// Remove nonexistent selection items, for same reason we waited till
|
||||
// the end to put up a dialog box.
|
||||
GW.ClearNonexistentSelectionItems();
|
||||
|
||||
if(deleted.requests > 0 || deleted.constraints > 0 || deleted.groups > 0) {
|
||||
// Don't display any errors until we've regenerated fully. The
|
||||
// sketch is not necessarily in a consistent state until we've
|
||||
|
|
|
@ -344,6 +344,7 @@ void TextWindow::ScreenChangeExtrudeSides(int link, DWORD v) {
|
|||
g->subtype = Group::EXTRUDE_ONE_SIDED;
|
||||
}
|
||||
SS.GW.GeneratePerSolving();
|
||||
SS.GW.ClearSuper();
|
||||
}
|
||||
void TextWindow::ShowGroupInfo(void) {
|
||||
Group *g = SS.group.FindById(shown->group);
|
||||
|
|
7
ui.h
7
ui.h
|
@ -120,6 +120,8 @@ public:
|
|||
MNU_GROUP_TRANS,
|
||||
// Constrain
|
||||
MNU_DISTANCE_DIA,
|
||||
MNU_ANGLE,
|
||||
MNU_OTHER_ANGLE,
|
||||
MNU_EQUAL,
|
||||
MNU_RATIO,
|
||||
MNU_ON_ENTITY,
|
||||
|
@ -227,11 +229,13 @@ public:
|
|||
Selection selection[MAX_SELECTED];
|
||||
void HitTestMakeSelection(Point2d mp);
|
||||
void ClearSelection(void);
|
||||
void ClearNonexistentSelectionItems(void);
|
||||
struct {
|
||||
hEntity point[MAX_SELECTED];
|
||||
hEntity entity[MAX_SELECTED];
|
||||
hEntity anyNormal[MAX_SELECTED];
|
||||
hEntity vector[MAX_SELECTED];
|
||||
hConstraint constraint[MAX_SELECTED];
|
||||
int points;
|
||||
int entities;
|
||||
int workplanes;
|
||||
|
@ -239,10 +243,13 @@ public:
|
|||
int circlesOrArcs;
|
||||
int anyNormals;
|
||||
int vectors;
|
||||
int constraints;
|
||||
int n;
|
||||
} gs;
|
||||
void GroupSelection(void);
|
||||
|
||||
void ClearSuper(void);
|
||||
|
||||
// This sets what gets displayed.
|
||||
bool showWorkplanes;
|
||||
bool showNormals;
|
||||
|
|
15
util.cpp
15
util.cpp
|
@ -307,17 +307,24 @@ Vector Vector::WithMagnitude(double v) {
|
|||
}
|
||||
}
|
||||
|
||||
Vector Vector::ProjectInto(hEntity wrkpl) {
|
||||
Vector Vector::ProjectVectorInto(hEntity wrkpl) {
|
||||
Entity *w = SS.GetEntity(wrkpl);
|
||||
Vector u = w->Normal()->NormalU();
|
||||
Vector v = w->Normal()->NormalV();
|
||||
|
||||
double up = this->Dot(u);
|
||||
double vp = this->Dot(v);
|
||||
|
||||
return (u.ScaledBy(up)).Plus(v.ScaledBy(vp));
|
||||
}
|
||||
|
||||
Vector Vector::ProjectInto(hEntity wrkpl) {
|
||||
Entity *w = SS.GetEntity(wrkpl);
|
||||
Vector p0 = w->WorkplaneGetOffset();
|
||||
|
||||
Vector f = this->Minus(p0);
|
||||
double up = f.Dot(u);
|
||||
double vp = f.Dot(v);
|
||||
|
||||
return p0.Plus((u.ScaledBy(up)).Plus(v.ScaledBy(vp)));
|
||||
return p0.Plus(f.ProjectVectorInto(wrkpl));
|
||||
}
|
||||
|
||||
Point2d Vector::Project2d(Vector u, Vector v) {
|
||||
|
|
Loading…
Reference in New Issue