Add tangency constraints, for line segments against arcs or cubics.
These are just a convenience, since it would be possible to get the same result by drawing a construction line. [git-p4: depot-paths = "//depot/solvespace/": change = 1836]
This commit is contained in:
parent
36870360cb
commit
88fc69116f
@ -31,6 +31,8 @@ char *Constraint::DescriptionString(void) {
|
|||||||
case SAME_ORIENTATION: s = "same-orientation"; break;
|
case SAME_ORIENTATION: s = "same-orientation"; break;
|
||||||
case ANGLE: s = "angle"; break;
|
case ANGLE: s = "angle"; break;
|
||||||
case PARALLEL: s = "parallel"; break;
|
case PARALLEL: s = "parallel"; break;
|
||||||
|
case ARC_LINE_TANGENT: s = "arc-line-tangent"; break;
|
||||||
|
case CUBIC_LINE_TANGENT:s = "cubic-line-tangent"; break;
|
||||||
case PERPENDICULAR: s = "perpendicular"; break;
|
case PERPENDICULAR: s = "perpendicular"; break;
|
||||||
case EQUAL_RADIUS: s = "eq-radius"; break;
|
case EQUAL_RADIUS: s = "eq-radius"; break;
|
||||||
case COMMENT: s = "comment"; break;
|
case COMMENT: s = "comment"; break;
|
||||||
@ -378,7 +380,7 @@ void Constraint::MenuConstrain(int id) {
|
|||||||
if(gs.constraints == 1 && gs.n == 0) {
|
if(gs.constraints == 1 && gs.n == 0) {
|
||||||
Constraint *c = SS.GetConstraint(gs.constraint[0]);
|
Constraint *c = SS.GetConstraint(gs.constraint[0]);
|
||||||
if(c->type == ANGLE) {
|
if(c->type == ANGLE) {
|
||||||
c->otherAngle = !(c->otherAngle);
|
c->other = !(c->other);
|
||||||
c->ModifyToSatisfy();
|
c->ModifyToSatisfy();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -405,7 +407,7 @@ void Constraint::MenuConstrain(int id) {
|
|||||||
c.entityA = gs.vector[0];
|
c.entityA = gs.vector[0];
|
||||||
c.entityB = gs.vector[1];
|
c.entityB = gs.vector[1];
|
||||||
c.valA = 0;
|
c.valA = 0;
|
||||||
c.otherAngle = true;
|
c.other = true;
|
||||||
} else {
|
} else {
|
||||||
Error("Bad selection for angle constraint.");
|
Error("Bad selection for angle constraint.");
|
||||||
return;
|
return;
|
||||||
@ -419,8 +421,56 @@ void Constraint::MenuConstrain(int id) {
|
|||||||
c.type = PARALLEL;
|
c.type = PARALLEL;
|
||||||
c.entityA = gs.vector[0];
|
c.entityA = gs.vector[0];
|
||||||
c.entityB = gs.vector[1];
|
c.entityB = gs.vector[1];
|
||||||
|
} else if(gs.lineSegments == 1 && gs.arcs == 1 && gs.n == 2) {
|
||||||
|
Entity *line = SS.GetEntity(gs.entity[0]);
|
||||||
|
Entity *arc = SS.GetEntity(gs.entity[1]);
|
||||||
|
if(line->type == Entity::ARC_OF_CIRCLE) {
|
||||||
|
SWAP(Entity *, line, arc);
|
||||||
|
}
|
||||||
|
Vector l0 = SS.GetEntity(line->point[0])->PointGetNum(),
|
||||||
|
l1 = SS.GetEntity(line->point[1])->PointGetNum();
|
||||||
|
Vector a1 = SS.GetEntity(arc->point[1])->PointGetNum(),
|
||||||
|
a2 = SS.GetEntity(arc->point[2])->PointGetNum();
|
||||||
|
|
||||||
|
if(l0.Equals(a1) || l1.Equals(a1)) {
|
||||||
|
c.other = false;
|
||||||
|
} else if(l0.Equals(a2) || l1.Equals(a2)) {
|
||||||
|
c.other = true;
|
||||||
} else {
|
} else {
|
||||||
Error("Bad selection for parallel constraint.");
|
Error("The tangent arc and line segment must share an "
|
||||||
|
"endpoint. Constrain them with Constrain -> "
|
||||||
|
"On Point before constraining tangent.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
c.type = ARC_LINE_TANGENT;
|
||||||
|
c.entityA = arc->h;
|
||||||
|
c.entityB = line->h;
|
||||||
|
} else if(gs.lineSegments == 1 && gs.cubics == 1 && gs.n == 2) {
|
||||||
|
Entity *line = SS.GetEntity(gs.entity[0]);
|
||||||
|
Entity *cubic = SS.GetEntity(gs.entity[1]);
|
||||||
|
if(line->type == Entity::CUBIC) {
|
||||||
|
SWAP(Entity *, line, cubic);
|
||||||
|
}
|
||||||
|
Vector l0 = SS.GetEntity(line->point[0])->PointGetNum(),
|
||||||
|
l1 = SS.GetEntity(line->point[1])->PointGetNum();
|
||||||
|
Vector a0 = SS.GetEntity(cubic->point[0])->PointGetNum(),
|
||||||
|
a3 = SS.GetEntity(cubic->point[3])->PointGetNum();
|
||||||
|
|
||||||
|
if(l0.Equals(a0) || l1.Equals(a0)) {
|
||||||
|
c.other = false;
|
||||||
|
} else if(l0.Equals(a3) || l1.Equals(a3)) {
|
||||||
|
c.other = true;
|
||||||
|
} else {
|
||||||
|
Error("The tangent cubic and line segment must share an "
|
||||||
|
"endpoint. Constrain them with Constrain -> "
|
||||||
|
"On Point before constraining tangent.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
c.type = CUBIC_LINE_TANGENT;
|
||||||
|
c.entityA = cubic->h;
|
||||||
|
c.entityB = line->h;
|
||||||
|
} else {
|
||||||
|
Error("Bad selection for parallel / tangent constraint.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AddConstraint(&c);
|
AddConstraint(&c);
|
||||||
@ -563,7 +613,7 @@ void Constraint::ModifyToSatisfy(void) {
|
|||||||
if(type == ANGLE) {
|
if(type == ANGLE) {
|
||||||
Vector a = SS.GetEntity(entityA)->VectorGetNum();
|
Vector a = SS.GetEntity(entityA)->VectorGetNum();
|
||||||
Vector b = SS.GetEntity(entityB)->VectorGetNum();
|
Vector b = SS.GetEntity(entityB)->VectorGetNum();
|
||||||
if(otherAngle) a = a.ScaledBy(-1);
|
if(other) a = a.ScaledBy(-1);
|
||||||
if(workplane.v != Entity::FREE_IN_3D.v) {
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
||||||
a = a.ProjectVectorInto(workplane);
|
a = a.ProjectVectorInto(workplane);
|
||||||
b = b.ProjectVectorInto(workplane);
|
b = b.ProjectVectorInto(workplane);
|
||||||
@ -961,7 +1011,7 @@ void Constraint::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||||||
Entity *b = SS.GetEntity(entityB);
|
Entity *b = SS.GetEntity(entityB);
|
||||||
ExprVector ae = a->VectorGetExprs();
|
ExprVector ae = a->VectorGetExprs();
|
||||||
ExprVector be = b->VectorGetExprs();
|
ExprVector be = b->VectorGetExprs();
|
||||||
if(otherAngle) ae = ae.ScaledBy(Expr::From(-1));
|
if(other) ae = ae.ScaledBy(Expr::From(-1));
|
||||||
Expr *c;
|
Expr *c;
|
||||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||||
Expr *mags = (ae.Magnitude())->Times(be.Magnitude());
|
Expr *mags = (ae.Magnitude())->Times(be.Magnitude());
|
||||||
@ -992,6 +1042,45 @@ void Constraint::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ARC_LINE_TANGENT: {
|
||||||
|
Entity *arc = SS.GetEntity(entityA);
|
||||||
|
Entity *line = SS.GetEntity(entityB);
|
||||||
|
|
||||||
|
ExprVector ac = SS.GetEntity(arc->point[0])->PointGetExprs();
|
||||||
|
ExprVector ap =
|
||||||
|
SS.GetEntity(arc->point[other ? 2 : 1])->PointGetExprs();
|
||||||
|
|
||||||
|
ExprVector ld = line->VectorGetExprs();
|
||||||
|
|
||||||
|
// The line is perpendicular to the radius
|
||||||
|
AddEq(l, ld.Dot(ac.Minus(ap)), 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case CUBIC_LINE_TANGENT: {
|
||||||
|
Entity *cubic = SS.GetEntity(entityA);
|
||||||
|
Entity *line = SS.GetEntity(entityB);
|
||||||
|
|
||||||
|
ExprVector endpoint =
|
||||||
|
SS.GetEntity(cubic->point[other ? 3 : 0])->PointGetExprs();
|
||||||
|
ExprVector ctrlpoint =
|
||||||
|
SS.GetEntity(cubic->point[other ? 2 : 1])->PointGetExprs();
|
||||||
|
|
||||||
|
ExprVector a = endpoint.Minus(ctrlpoint);
|
||||||
|
|
||||||
|
ExprVector b = line->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;
|
||||||
|
}
|
||||||
|
|
||||||
case PARALLEL: {
|
case PARALLEL: {
|
||||||
Entity *ea = SS.GetEntity(entityA), *eb = SS.GetEntity(entityB);
|
Entity *ea = SS.GetEntity(entityA), *eb = SS.GetEntity(entityB);
|
||||||
if(eb->group.v != group.v) {
|
if(eb->group.v != group.v) {
|
||||||
|
5
draw.cpp
5
draw.cpp
@ -791,8 +791,13 @@ void GraphicsWindow::GroupSelection(void) {
|
|||||||
switch(e->type) {
|
switch(e->type) {
|
||||||
case Entity::WORKPLANE: (gs.workplanes)++; break;
|
case Entity::WORKPLANE: (gs.workplanes)++; break;
|
||||||
case Entity::LINE_SEGMENT: (gs.lineSegments)++; break;
|
case Entity::LINE_SEGMENT: (gs.lineSegments)++; break;
|
||||||
|
case Entity::CUBIC: (gs.cubics)++; break;
|
||||||
|
|
||||||
case Entity::ARC_OF_CIRCLE:
|
case Entity::ARC_OF_CIRCLE:
|
||||||
|
(gs.circlesOrArcs)++;
|
||||||
|
(gs.arcs)++;
|
||||||
|
break;
|
||||||
|
|
||||||
case Entity::CIRCLE: (gs.circlesOrArcs)++; break;
|
case Entity::CIRCLE: (gs.circlesOrArcs)++; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -305,7 +305,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||||||
Vector b0 = b->VectorGetRefPoint();
|
Vector b0 = b->VectorGetRefPoint();
|
||||||
Vector da = a->VectorGetNum();
|
Vector da = a->VectorGetNum();
|
||||||
Vector db = b->VectorGetNum();
|
Vector db = b->VectorGetNum();
|
||||||
if(otherAngle) da = da.ScaledBy(-1);
|
if(other) da = da.ScaledBy(-1);
|
||||||
|
|
||||||
if(workplane.v != Entity::FREE_IN_3D.v) {
|
if(workplane.v != Entity::FREE_IN_3D.v) {
|
||||||
a0 = a0.ProjectInto(workplane);
|
a0 = a0.ProjectInto(workplane);
|
||||||
@ -411,6 +411,55 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case CUBIC_LINE_TANGENT:
|
||||||
|
case ARC_LINE_TANGENT: {
|
||||||
|
Vector textAt, u, v;
|
||||||
|
|
||||||
|
if(type == ARC_LINE_TANGENT) {
|
||||||
|
Entity *arc = SS.GetEntity(entityA);
|
||||||
|
Entity *norm = SS.GetEntity(arc->normal);
|
||||||
|
Vector c = SS.GetEntity(arc->point[0])->PointGetNum();
|
||||||
|
Vector p =
|
||||||
|
SS.GetEntity(arc->point[other ? 2 : 1])->PointGetNum();
|
||||||
|
Vector r = p.Minus(c);
|
||||||
|
textAt = p.Plus(r.WithMagnitude(14/SS.GW.scale));
|
||||||
|
u = norm->NormalU();
|
||||||
|
v = norm->NormalV();
|
||||||
|
} else {
|
||||||
|
Vector n;
|
||||||
|
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||||
|
u = gr;
|
||||||
|
v = gu;
|
||||||
|
n = gn;
|
||||||
|
} else {
|
||||||
|
Entity *wn = SS.GetEntity(workplane)->Normal();
|
||||||
|
u = wn->NormalU();
|
||||||
|
v = wn->NormalV();
|
||||||
|
n = wn->NormalN();
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity *cubic = SS.GetEntity(entityA);
|
||||||
|
Vector p =
|
||||||
|
SS.GetEntity(cubic->point[other ? 3 : 0])->PointGetNum();
|
||||||
|
Vector dir = SS.GetEntity(entityB)->VectorGetNum();
|
||||||
|
Vector out = n.Cross(dir);
|
||||||
|
textAt = p.Plus(out.WithMagnitude(14/SS.GW.scale));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dogd.drawing) {
|
||||||
|
glPushMatrix();
|
||||||
|
glxTranslatev(textAt);
|
||||||
|
glxOntoWorkplane(u, v);
|
||||||
|
glxWriteTextRefCenter("T");
|
||||||
|
glPopMatrix();
|
||||||
|
} else {
|
||||||
|
dogd.refp = textAt;
|
||||||
|
Point2d ref = SS.GW.ProjectPoint(dogd.refp);
|
||||||
|
dogd.dmin = min(dogd.dmin, ref.DistanceTo(dogd.mp)-10);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
2
file.cpp
2
file.cpp
@ -132,7 +132,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.other", 'b', &(SS.sv.c.other) },
|
||||||
{ 'c', "Constraint.reference", 'b', &(SS.sv.c.reference) },
|
{ 'c', "Constraint.reference", 'b', &(SS.sv.c.reference) },
|
||||||
{ 'c', "Constraint.comment", 'N', &(SS.sv.c.comment) },
|
{ 'c', "Constraint.comment", 'N', &(SS.sv.c.comment) },
|
||||||
{ 'c', "Constraint.disp.offset.x", 'f', &(SS.sv.c.disp.offset.x) },
|
{ 'c', "Constraint.disp.offset.x", 'f', &(SS.sv.c.disp.offset.x) },
|
||||||
|
@ -25,11 +25,11 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||||||
{ 0, "&Edit", 0, NULL },
|
{ 0, "&Edit", 0, NULL },
|
||||||
{ 1, "&Undo\tCtrl+Z", MNU_UNDO, 'Z'|C, mEdit },
|
{ 1, "&Undo\tCtrl+Z", MNU_UNDO, 'Z'|C, mEdit },
|
||||||
{ 1, "&Redo\tCtrl+Y", MNU_REDO, 'Y'|C, mEdit },
|
{ 1, "&Redo\tCtrl+Y", MNU_REDO, 'Y'|C, mEdit },
|
||||||
|
{ 1, "Re&generate All\tSpace", MNU_REGEN_ALL, ' ', mEdit },
|
||||||
{ 1, NULL, 0, NULL },
|
{ 1, NULL, 0, NULL },
|
||||||
{ 1, "&Delete\tDel", MNU_DELETE, 127, mEdit },
|
{ 1, "&Delete\tDel", MNU_DELETE, 127, mEdit },
|
||||||
{ 1, NULL, 0, NULL },
|
{ 1, NULL, 0, NULL },
|
||||||
{ 1, "&Unselect All\tEsc", MNU_UNSELECT_ALL, 27, mEdit },
|
{ 1, "&Unselect All\tEsc", MNU_UNSELECT_ALL, 27, mEdit },
|
||||||
{ 1, "Re&generate All\tSpace", MNU_REGEN_ALL, ' ', mEdit },
|
|
||||||
|
|
||||||
{ 0, "&View", 0, NULL },
|
{ 0, "&View", 0, NULL },
|
||||||
{ 1, "Zoom &In\t+", MNU_ZOOM_IN, '+', mView },
|
{ 1, "Zoom &In\t+", MNU_ZOOM_IN, '+', mView },
|
||||||
@ -87,7 +87,7 @@ const GraphicsWindow::MenuEntry GraphicsWindow::menu[] = {
|
|||||||
{ 1, "Length Ra&tio\tZ", MNU_RATIO, 'Z', mCon },
|
{ 1, "Length Ra&tio\tZ", MNU_RATIO, 'Z', mCon },
|
||||||
{ 1, "At &Midpoint\tM", MNU_AT_MIDPOINT, 'M', mCon },
|
{ 1, "At &Midpoint\tM", MNU_AT_MIDPOINT, 'M', mCon },
|
||||||
{ 1, "S&ymmetric\tY", MNU_SYMMETRIC, 'Y', mCon },
|
{ 1, "S&ymmetric\tY", MNU_SYMMETRIC, 'Y', mCon },
|
||||||
{ 1, "Para&llel\tL", MNU_PARALLEL, 'L', mCon },
|
{ 1, "Para&llel / Tangent\tL", MNU_PARALLEL, 'L', mCon },
|
||||||
{ 1, "&Perpendicular\t[", MNU_PERPENDICULAR, '[', mCon },
|
{ 1, "&Perpendicular\t[", MNU_PERPENDICULAR, '[', mCon },
|
||||||
{ 1, "Same Orient&ation\tX", MNU_ORIENTED_SAME, 'X', mCon },
|
{ 1, "Same Orient&ation\tX", MNU_ORIENTED_SAME, 'X', mCon },
|
||||||
{ 1, NULL, 0, NULL },
|
{ 1, NULL, 0, NULL },
|
||||||
|
2
mesh.cpp
2
mesh.cpp
@ -619,7 +619,7 @@ void SKdNode::MakeCertainEdgesInto(SEdgeList *sel, bool emphasized) {
|
|||||||
FindEdgeOn(a, b, &n, &nOther, tr->meta, cnt++);
|
FindEdgeOn(a, b, &n, &nOther, tr->meta, cnt++);
|
||||||
if(n != 1) {
|
if(n != 1) {
|
||||||
if(!emphasized) {
|
if(!emphasized) {
|
||||||
sel->AddEdge(a, b);
|
if(n == 0) sel->AddEdge(a, b);
|
||||||
} else {
|
} else {
|
||||||
dbp("hanging: n=%d (%.3f %.3f %.3f) (%.3f %.3f %.3f)",
|
dbp("hanging: n=%d (%.3f %.3f %.3f) (%.3f %.3f %.3f)",
|
||||||
n, CO(a), CO(b));
|
n, CO(a), CO(b));
|
||||||
|
4
sketch.h
4
sketch.h
@ -463,6 +463,8 @@ public:
|
|||||||
static const int ANGLE = 120;
|
static const int ANGLE = 120;
|
||||||
static const int PARALLEL = 121;
|
static const int PARALLEL = 121;
|
||||||
static const int PERPENDICULAR = 122;
|
static const int PERPENDICULAR = 122;
|
||||||
|
static const int ARC_LINE_TANGENT = 123;
|
||||||
|
static const int CUBIC_LINE_TANGENT = 124;
|
||||||
static const int EQUAL_RADIUS = 130;
|
static const int EQUAL_RADIUS = 130;
|
||||||
|
|
||||||
static const int COMMENT = 1000;
|
static const int COMMENT = 1000;
|
||||||
@ -482,7 +484,7 @@ public:
|
|||||||
hEntity ptC;
|
hEntity ptC;
|
||||||
hEntity entityA;
|
hEntity entityA;
|
||||||
hEntity entityB;
|
hEntity entityB;
|
||||||
bool otherAngle;
|
bool other;
|
||||||
|
|
||||||
bool reference; // a ref dimension, that generates no eqs
|
bool reference; // a ref dimension, that generates no eqs
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user