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);
|
AddConstraint(&c);
|
||||||
break;
|
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:
|
case GraphicsWindow::MNU_PARALLEL:
|
||||||
if(gs.vectors == 2 && gs.n == 2) {
|
if(gs.vectors == 2 && gs.n == 2) {
|
||||||
c.type = PARALLEL;
|
c.type = PARALLEL;
|
||||||
|
@ -374,21 +401,37 @@ ExprVector Constraint::PointInThreeSpace(hEntity workplane, Expr *u, Expr *v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Constraint::ModifyToSatisfy(void) {
|
void Constraint::ModifyToSatisfy(void) {
|
||||||
IdList<Equation,hEquation> l;
|
if(type == ANGLE) {
|
||||||
// An uninit IdList could lead us to free some random address, bad.
|
Vector a = SS.GetEntity(entityA)->VectorGetNum();
|
||||||
memset(&l, 0, sizeof(l));
|
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);
|
Generate(&l);
|
||||||
if(l.n != 1) oops();
|
if(l.n != 1) oops();
|
||||||
|
|
||||||
// These equations are written in the form f(...) - d = 0, where
|
// These equations are written in the form f(...) - d = 0, where
|
||||||
// d is the value of the exprA.
|
// d is the value of the exprA.
|
||||||
double v = (l.elem[0].e)->Eval();
|
double v = (l.elem[0].e)->Eval();
|
||||||
double nd = exprA->Eval() + v;
|
double nd = exprA->Eval() + v;
|
||||||
Expr::FreeKeep(&exprA);
|
Expr::FreeKeep(&exprA);
|
||||||
exprA = Expr::FromConstant(nd)->DeepCopyKeep();
|
exprA = Expr::FromConstant(nd)->DeepCopyKeep();
|
||||||
|
|
||||||
l.Clear();
|
l.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Constraint::AddEq(IdList<Equation,hEquation> *l, Expr *expr, int index) {
|
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) {
|
void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
||||||
|
Expr *exA = NULL;
|
||||||
|
if(exprA) exA = exprA->DeepCopy();
|
||||||
|
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case PT_PT_DISTANCE:
|
case PT_PT_DISTANCE:
|
||||||
AddEq(l, Distance(workplane, ptA, ptB)->Minus(exprA), 0);
|
AddEq(l, Distance(workplane, ptA, ptB)->Minus(exA), 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PT_LINE_DISTANCE:
|
case PT_LINE_DISTANCE:
|
||||||
AddEq(l,
|
AddEq(l,
|
||||||
PointLineDistance(workplane, ptA, entityA)->Minus(exprA), 0);
|
PointLineDistance(workplane, ptA, entityA)->Minus(exA), 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PT_PLANE_DISTANCE: {
|
case PT_PLANE_DISTANCE: {
|
||||||
ExprVector pt = SS.GetEntity(ptA)->PointGetExprs();
|
ExprVector pt = SS.GetEntity(ptA)->PointGetExprs();
|
||||||
AddEq(l, (PointPlaneDistance(pt, entityA))->Minus(exprA), 0);
|
AddEq(l, (PointPlaneDistance(pt, entityA))->Minus(exA), 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,14 +474,14 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
||||||
Entity *b = SS.GetEntity(entityB);
|
Entity *b = SS.GetEntity(entityB);
|
||||||
Expr *la = Distance(workplane, a->point[0], a->point[1]);
|
Expr *la = Distance(workplane, a->point[0], a->point[1]);
|
||||||
Expr *lb = Distance(workplane, b->point[0], b->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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case DIAMETER: {
|
case DIAMETER: {
|
||||||
Entity *circle = SS.GetEntity(entityA);
|
Entity *circle = SS.GetEntity(entityA);
|
||||||
Expr *r = circle->CircleGetRadiusExpr();
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -656,6 +702,34 @@ void Constraint::Generate(IdList<Equation,hEquation> *l) {
|
||||||
break;
|
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: {
|
case PARALLEL: {
|
||||||
ExprVector a = SS.GetEntity(entityA)->VectorGetExprs();
|
ExprVector a = SS.GetEntity(entityA)->VectorGetExprs();
|
||||||
ExprVector b = SS.GetEntity(entityB)->VectorGetExprs();
|
ExprVector b = SS.GetEntity(entityB)->VectorGetExprs();
|
||||||
|
|
|
@ -7,6 +7,7 @@ bool Constraint::HasLabel(void) {
|
||||||
case PT_PT_DISTANCE:
|
case PT_PT_DISTANCE:
|
||||||
case DIAMETER:
|
case DIAMETER:
|
||||||
case LENGTH_RATIO:
|
case LENGTH_RATIO:
|
||||||
|
case ANGLE:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -247,6 +248,83 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
||||||
break;
|
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: {
|
case PARALLEL: {
|
||||||
for(int i = 0; i < 2; i++) {
|
for(int i = 0; i < 2; i++) {
|
||||||
Entity *e = SS.GetEntity(i == 0 ? entityA : entityB);
|
Entity *e = SS.GetEntity(i == 0 ? entityA : entityB);
|
||||||
|
|
1
dsc.h
1
dsc.h
|
@ -53,6 +53,7 @@ public:
|
||||||
Vector WithMagnitude(double s);
|
Vector WithMagnitude(double s);
|
||||||
Vector ScaledBy(double s);
|
Vector ScaledBy(double s);
|
||||||
Vector ProjectInto(hEntity wrkpl);
|
Vector ProjectInto(hEntity wrkpl);
|
||||||
|
Vector ProjectVectorInto(hEntity wrkpl);
|
||||||
double DivPivoting(Vector delta);
|
double DivPivoting(Vector delta);
|
||||||
Vector ClosestOrtho(void);
|
Vector ClosestOrtho(void);
|
||||||
Point2d Project2d(Vector u, Vector v);
|
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.ptC.v", 'x', &(SS.sv.c.ptC.v) },
|
||||||
{ 'c', "Constraint.entityA.v", 'x', &(SS.sv.c.entityA.v) },
|
{ 'c', "Constraint.entityA.v", 'x', &(SS.sv.c.entityA.v) },
|
||||||
{ 'c', "Constraint.entityB.v", 'x', &(SS.sv.c.entityB.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.x", 'f', &(SS.sv.c.disp.offset.x) },
|
||||||
{ 'c', "Constraint.disp.offset.y", 'f', &(SS.sv.c.disp.offset.y) },
|
{ 'c', "Constraint.disp.offset.y", 'f', &(SS.sv.c.disp.offset.y) },
|
||||||
{ 'c', "Constraint.disp.offset.z", 'f', &(SS.sv.c.disp.offset.z) },
|
{ '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 },
|
{ 0, "&Constrain", 0, NULL },
|
||||||
{ 1, "&Distance / Diameter\tShift+D", MNU_DISTANCE_DIA, 'D'|S, mCon },
|
{ 1, "&Distance / Diameter\tShift+D", MNU_DISTANCE_DIA, 'D'|S, mCon },
|
||||||
{ 1, "A&ngle\tShift+N", 0, 'N'|S, NULL },
|
{ 1, "A&ngle\tShift+N", MNU_ANGLE, 'N'|S, mCon },
|
||||||
{ 1, "Other S&upplementary Angle\tShift+U", 0, 'U'|S, NULL },
|
{ 1, "Other S&upplementary Angle\tShift+U", MNU_OTHER_ANGLE, 'U'|S, mCon },
|
||||||
{ 1, NULL, 0, NULL },
|
{ 1, NULL, 0, NULL },
|
||||||
{ 1, "&Horizontal\tShift+H", MNU_HORIZONTAL, 'H'|S, mCon },
|
{ 1, "&Horizontal\tShift+H", MNU_HORIZONTAL, 'H'|S, mCon },
|
||||||
{ 1, "&Vertical\tShift+V", MNU_VERTICAL, 'V'|S, mCon },
|
{ 1, "&Vertical\tShift+V", MNU_VERTICAL, 'V'|S, mCon },
|
||||||
|
@ -302,8 +302,7 @@ void GraphicsWindow::MenuEdit(int id) {
|
||||||
SS.constraint.RemoveTagged();
|
SS.constraint.RemoveTagged();
|
||||||
|
|
||||||
// Forget any mention of the just-deleted entity
|
// Forget any mention of the just-deleted entity
|
||||||
SS.GW.ClearSelection();
|
SS.GW.ClearSuper();
|
||||||
SS.GW.hover.Clear();
|
|
||||||
// And regenerate to get rid of what it generates, plus anything
|
// And regenerate to get rid of what it generates, plus anything
|
||||||
// that references it (since the regen code checks for that).
|
// that references it (since the regen code checks for that).
|
||||||
SS.GW.GeneratePerSolving();
|
SS.GW.GeneratePerSolving();
|
||||||
|
@ -633,6 +632,13 @@ void GraphicsWindow::Selection::Draw(void) {
|
||||||
if(constraint.v) SS.GetConstraint(constraint)->Draw();
|
if(constraint.v) SS.GetConstraint(constraint)->Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GraphicsWindow::ClearSuper(void) {
|
||||||
|
ClearPending();
|
||||||
|
ClearSelection();
|
||||||
|
hover.Clear();
|
||||||
|
EnsureValidActives();
|
||||||
|
}
|
||||||
|
|
||||||
void GraphicsWindow::ClearPending(void) {
|
void GraphicsWindow::ClearPending(void) {
|
||||||
memset(&pending, 0, sizeof(pending));
|
memset(&pending, 0, sizeof(pending));
|
||||||
}
|
}
|
||||||
|
@ -680,6 +686,22 @@ void GraphicsWindow::ClearSelection(void) {
|
||||||
InvalidateGraphics();
|
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) {
|
void GraphicsWindow::GroupSelection(void) {
|
||||||
memset(&gs, 0, sizeof(gs));
|
memset(&gs, 0, sizeof(gs));
|
||||||
int i;
|
int i;
|
||||||
|
@ -718,6 +740,9 @@ void GraphicsWindow::GroupSelection(void) {
|
||||||
case Entity::CIRCLE: (gs.circlesOrArcs)++; break;
|
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);
|
hr = AddRequest(Request::DATUM_POINT);
|
||||||
SS.GetEntity(hr.entity(0))->PointForceTo(v);
|
SS.GetEntity(hr.entity(0))->PointForceTo(v);
|
||||||
|
|
||||||
ClearSelection(); hover.Clear();
|
ClearSuper();
|
||||||
|
|
||||||
pending.operation = 0;
|
pending.operation = 0;
|
||||||
break;
|
break;
|
||||||
|
@ -804,7 +829,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
SS.GetEntity(hr.entity(1))->PointForceTo(v);
|
||||||
ConstrainPointByHovered(hr.entity(1));
|
ConstrainPointByHovered(hr.entity(1));
|
||||||
|
|
||||||
ClearSelection(); hover.Clear();
|
ClearSuper();
|
||||||
|
|
||||||
pending.operation = DRAGGING_NEW_LINE_POINT;
|
pending.operation = DRAGGING_NEW_LINE_POINT;
|
||||||
pending.point = hr.entity(2);
|
pending.point = hr.entity(2);
|
||||||
|
@ -848,9 +873,8 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp));
|
Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp));
|
||||||
ConstrainPointByHovered(hr.entity(1));
|
ConstrainPointByHovered(hr.entity(1));
|
||||||
|
|
||||||
ClearSelection(); hover.Clear();
|
ClearSuper();
|
||||||
|
|
||||||
ClearPending();
|
|
||||||
pending.operation = DRAGGING_NEW_RADIUS;
|
pending.operation = DRAGGING_NEW_RADIUS;
|
||||||
pending.circle = hr.entity(0);
|
pending.circle = hr.entity(0);
|
||||||
pending.description = "click to set radius";
|
pending.description = "click to set radius";
|
||||||
|
@ -869,9 +893,8 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
SS.GetEntity(hr.entity(3))->PointForceTo(v);
|
SS.GetEntity(hr.entity(3))->PointForceTo(v);
|
||||||
ConstrainPointByHovered(hr.entity(2));
|
ConstrainPointByHovered(hr.entity(2));
|
||||||
|
|
||||||
ClearSelection(); hover.Clear();
|
ClearSuper();
|
||||||
|
|
||||||
ClearPending();
|
|
||||||
pending.operation = DRAGGING_NEW_ARC_POINT;
|
pending.operation = DRAGGING_NEW_ARC_POINT;
|
||||||
pending.point = hr.entity(3);
|
pending.point = hr.entity(3);
|
||||||
pending.description = "click to place point";
|
pending.description = "click to place point";
|
||||||
|
@ -885,7 +908,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
SS.GetEntity(hr.entity(4))->PointForceTo(v);
|
SS.GetEntity(hr.entity(4))->PointForceTo(v);
|
||||||
ConstrainPointByHovered(hr.entity(1));
|
ConstrainPointByHovered(hr.entity(1));
|
||||||
|
|
||||||
ClearSelection(); hover.Clear();
|
ClearSuper();
|
||||||
|
|
||||||
pending.operation = DRAGGING_NEW_CUBIC_POINT;
|
pending.operation = DRAGGING_NEW_CUBIC_POINT;
|
||||||
pending.point = hr.entity(4);
|
pending.point = hr.entity(4);
|
||||||
|
@ -899,8 +922,7 @@ void GraphicsWindow::MouseLeftDown(double mx, double my) {
|
||||||
Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp));
|
Quaternion::MakeFrom(SS.GW.projRight, SS.GW.projUp));
|
||||||
ConstrainPointByHovered(hr.entity(1));
|
ConstrainPointByHovered(hr.entity(1));
|
||||||
|
|
||||||
ClearSelection(); hover.Clear();
|
ClearSuper();
|
||||||
ClearPending();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DRAGGING_RADIUS:
|
case DRAGGING_RADIUS:
|
||||||
|
@ -986,12 +1008,13 @@ void GraphicsWindow::MouseLeftDoubleClick(double mx, double my) {
|
||||||
if(GraphicsEditControlIsVisible()) return;
|
if(GraphicsEditControlIsVisible()) return;
|
||||||
|
|
||||||
if(hover.constraint.v) {
|
if(hover.constraint.v) {
|
||||||
ClearSelection();
|
|
||||||
Constraint *c = SS.GetConstraint(hover.constraint);
|
Constraint *c = SS.GetConstraint(hover.constraint);
|
||||||
Vector p3 = c->GetLabelPos();
|
Vector p3 = c->GetLabelPos();
|
||||||
Point2d p2 = ProjectPoint(p3);
|
Point2d p2 = ProjectPoint(p3);
|
||||||
ShowGraphicsEditControl((int)p2.x, (int)p2.y, c->exprA->Print());
|
ShowGraphicsEditControl((int)p2.x, (int)p2.y, c->exprA->Print());
|
||||||
constraintBeingEdited = hover.constraint;
|
constraintBeingEdited = hover.constraint;
|
||||||
|
|
||||||
|
ClearSuper();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -497,7 +497,9 @@ void Group::Draw(void) {
|
||||||
int i;
|
int i;
|
||||||
glEnable(GL_LIGHTING);
|
glEnable(GL_LIGHTING);
|
||||||
GLfloat vec[] = { 0.3f, 0.3f, 0.3f, 1.0 };
|
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++) {
|
for(i = 0; i < faces.n; i++) {
|
||||||
glxFillPolygon(&(faces.elem[i]));
|
glxFillPolygon(&(faces.elem[i]));
|
||||||
#if 0
|
#if 0
|
||||||
|
|
4
sketch.h
4
sketch.h
|
@ -343,7 +343,8 @@ public:
|
||||||
static const int DIAMETER = 90;
|
static const int DIAMETER = 90;
|
||||||
static const int PT_ON_CIRCLE = 100;
|
static const int PT_ON_CIRCLE = 100;
|
||||||
static const int SAME_ORIENTATION = 110;
|
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;
|
static const int EQUAL_RADIUS = 130;
|
||||||
|
|
||||||
int tag;
|
int tag;
|
||||||
|
@ -362,6 +363,7 @@ public:
|
||||||
hEntity ptC;
|
hEntity ptC;
|
||||||
hEntity entityA;
|
hEntity entityA;
|
||||||
hEntity entityB;
|
hEntity entityB;
|
||||||
|
bool otherAngle;
|
||||||
|
|
||||||
// These define how the constraint is drawn on-screen.
|
// These define how the constraint is drawn on-screen.
|
||||||
struct {
|
struct {
|
||||||
|
|
|
@ -184,6 +184,10 @@ void SolveSpace::GenerateAll(bool andSolve) {
|
||||||
prev.Clear();
|
prev.Clear();
|
||||||
InvalidateGraphics();
|
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) {
|
if(deleted.requests > 0 || deleted.constraints > 0 || deleted.groups > 0) {
|
||||||
// Don't display any errors until we've regenerated fully. The
|
// Don't display any errors until we've regenerated fully. The
|
||||||
// sketch is not necessarily in a consistent state until we've
|
// 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;
|
g->subtype = Group::EXTRUDE_ONE_SIDED;
|
||||||
}
|
}
|
||||||
SS.GW.GeneratePerSolving();
|
SS.GW.GeneratePerSolving();
|
||||||
|
SS.GW.ClearSuper();
|
||||||
}
|
}
|
||||||
void TextWindow::ShowGroupInfo(void) {
|
void TextWindow::ShowGroupInfo(void) {
|
||||||
Group *g = SS.group.FindById(shown->group);
|
Group *g = SS.group.FindById(shown->group);
|
||||||
|
|
7
ui.h
7
ui.h
|
@ -120,6 +120,8 @@ public:
|
||||||
MNU_GROUP_TRANS,
|
MNU_GROUP_TRANS,
|
||||||
// Constrain
|
// Constrain
|
||||||
MNU_DISTANCE_DIA,
|
MNU_DISTANCE_DIA,
|
||||||
|
MNU_ANGLE,
|
||||||
|
MNU_OTHER_ANGLE,
|
||||||
MNU_EQUAL,
|
MNU_EQUAL,
|
||||||
MNU_RATIO,
|
MNU_RATIO,
|
||||||
MNU_ON_ENTITY,
|
MNU_ON_ENTITY,
|
||||||
|
@ -227,11 +229,13 @@ public:
|
||||||
Selection selection[MAX_SELECTED];
|
Selection selection[MAX_SELECTED];
|
||||||
void HitTestMakeSelection(Point2d mp);
|
void HitTestMakeSelection(Point2d mp);
|
||||||
void ClearSelection(void);
|
void ClearSelection(void);
|
||||||
|
void ClearNonexistentSelectionItems(void);
|
||||||
struct {
|
struct {
|
||||||
hEntity point[MAX_SELECTED];
|
hEntity point[MAX_SELECTED];
|
||||||
hEntity entity[MAX_SELECTED];
|
hEntity entity[MAX_SELECTED];
|
||||||
hEntity anyNormal[MAX_SELECTED];
|
hEntity anyNormal[MAX_SELECTED];
|
||||||
hEntity vector[MAX_SELECTED];
|
hEntity vector[MAX_SELECTED];
|
||||||
|
hConstraint constraint[MAX_SELECTED];
|
||||||
int points;
|
int points;
|
||||||
int entities;
|
int entities;
|
||||||
int workplanes;
|
int workplanes;
|
||||||
|
@ -239,10 +243,13 @@ public:
|
||||||
int circlesOrArcs;
|
int circlesOrArcs;
|
||||||
int anyNormals;
|
int anyNormals;
|
||||||
int vectors;
|
int vectors;
|
||||||
|
int constraints;
|
||||||
int n;
|
int n;
|
||||||
} gs;
|
} gs;
|
||||||
void GroupSelection(void);
|
void GroupSelection(void);
|
||||||
|
|
||||||
|
void ClearSuper(void);
|
||||||
|
|
||||||
// This sets what gets displayed.
|
// This sets what gets displayed.
|
||||||
bool showWorkplanes;
|
bool showWorkplanes;
|
||||||
bool showNormals;
|
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);
|
Entity *w = SS.GetEntity(wrkpl);
|
||||||
Vector u = w->Normal()->NormalU();
|
Vector u = w->Normal()->NormalU();
|
||||||
Vector v = w->Normal()->NormalV();
|
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 p0 = w->WorkplaneGetOffset();
|
||||||
|
|
||||||
Vector f = this->Minus(p0);
|
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) {
|
Point2d Vector::Project2d(Vector u, Vector v) {
|
||||||
|
|
Loading…
Reference in New Issue