Add a constraint for tangency between any combination of arcs
and cubics. Also add that to the library interface. It might have been better to use a single constraint for that, plus all the line-curve or line-line cases, but it would break backwards compatibility if I did that now, and perhaps be confusing with the 'other' member (which is meaningless for lines) anyways. [git-p4: depot-paths = "//depot/solvespace/": change = 2141]solver
parent
9f7ff34b98
commit
949df4d139
|
@ -14,9 +14,9 @@ char *Constraint::DescriptionString(void) {
|
|||
case PT_IN_PLANE: s = "pt-in-plane"; break;
|
||||
case PT_ON_LINE: s = "pt-on-line"; break;
|
||||
case PT_ON_FACE: s = "pt-on-face"; break;
|
||||
case EQUAL_LENGTH_LINES:s = "eq-length"; break;
|
||||
case EQUAL_LENGTH_LINES: s = "eq-length"; break;
|
||||
case EQ_LEN_PT_LINE_D: s = "eq-length-and-pt-ln-dist"; break;
|
||||
case EQ_PT_LN_DISTANCES:s = "eq-pt-line-distances"; break;
|
||||
case EQ_PT_LN_DISTANCES: s = "eq-pt-line-distances"; break;
|
||||
case LENGTH_RATIO: s = "length-ratio"; break;
|
||||
case SYMMETRIC: s = "symmetric"; break;
|
||||
case SYMMETRIC_HORIZ: s = "symmetric-h"; break;
|
||||
|
@ -31,11 +31,12 @@ char *Constraint::DescriptionString(void) {
|
|||
case ANGLE: s = "angle"; 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 CUBIC_LINE_TANGENT: s = "cubic-line-tangent"; break;
|
||||
case CURVE_CURVE_TANGENT: s = "curve-curve-tangent"; break;
|
||||
case PERPENDICULAR: s = "perpendicular"; break;
|
||||
case EQUAL_RADIUS: s = "eq-radius"; break;
|
||||
case EQUAL_ANGLE: s = "eq-angle"; break;
|
||||
case EQUAL_LINE_ARC_LEN:s = "eq-line-len-arc-len"; break;
|
||||
case EQUAL_LINE_ARC_LEN: s = "eq-line-len-arc-len"; break;
|
||||
case WHERE_DRAGGED: s = "lock-where-dragged"; break;
|
||||
case COMMENT: s = "comment"; break;
|
||||
default: s = "???"; break;
|
||||
|
@ -616,16 +617,42 @@ void Constraint::MenuConstrain(int id) {
|
|||
c.type = CUBIC_LINE_TANGENT;
|
||||
c.entityA = cubic->h;
|
||||
c.entityB = line->h;
|
||||
} else if(gs.cubics + gs.arcs == 2 && gs.n == 2) {
|
||||
if(!SS.GW.LockedInWorkplane()) {
|
||||
Error("Curve-curve tangency must apply in workplane.");
|
||||
return;
|
||||
}
|
||||
Entity *eA = SK.GetEntity(gs.entity[0]),
|
||||
*eB = SK.GetEntity(gs.entity[1]);
|
||||
Vector as = eA->EndpointStart(),
|
||||
af = eA->EndpointFinish(),
|
||||
bs = eB->EndpointStart(),
|
||||
bf = eB->EndpointFinish();
|
||||
if(as.Equals(bs)) {
|
||||
c.other = false; c.other2 = false;
|
||||
} else if(as.Equals(bf)) {
|
||||
c.other = false; c.other2 = true;
|
||||
} else if(af.Equals(bs)) {
|
||||
c.other = true; c.other2 = false;
|
||||
} else if(af.Equals(bf)) {
|
||||
c.other = true; c.other2 = true;
|
||||
} else {
|
||||
Error("The curves must share an endpoint. Constrain them "
|
||||
"with Constrain -> On Point before constraining "
|
||||
"tangent.");
|
||||
return;
|
||||
}
|
||||
c.type = CURVE_CURVE_TANGENT;
|
||||
c.entityA = eA->h;
|
||||
c.entityB = eB->h;
|
||||
} else {
|
||||
Error("Bad selection for parallel / tangent constraint. This "
|
||||
"constraint can apply to:\n\n"
|
||||
" * two line segments (parallel)\n"
|
||||
" * a line segment and a normal (parallel)\n"
|
||||
" * two normals (parallel)\n"
|
||||
" * a line segment and an arc, that share an endpoint "
|
||||
"(tangent)\n"
|
||||
" * a line segment and a cubic bezier, that share an "
|
||||
"endpoint (tangent)\n");
|
||||
" * two line segments, arcs, or beziers, that share "
|
||||
"an endpoint (tangent)\n");
|
||||
return;
|
||||
}
|
||||
AddConstraint(&c);
|
||||
|
|
|
@ -689,6 +689,44 @@ void ConstraintBase::GenerateReal(IdList<Equation,hEquation> *l) {
|
|||
break;
|
||||
}
|
||||
|
||||
case CURVE_CURVE_TANGENT: {
|
||||
bool parallel = true;
|
||||
int i;
|
||||
ExprVector dir[2];
|
||||
for(i = 0; i < 2; i++) {
|
||||
EntityBase *e = SK.GetEntity((i == 0) ? entityA : entityB);
|
||||
bool oth = (i == 0) ? other : other2;
|
||||
|
||||
if(e->type == Entity::ARC_OF_CIRCLE) {
|
||||
ExprVector center, endpoint;
|
||||
center = SK.GetEntity(e->point[0])->PointGetExprs();
|
||||
endpoint =
|
||||
SK.GetEntity(e->point[oth ? 2 : 1])->PointGetExprs();
|
||||
dir[i] = endpoint.Minus(center);
|
||||
// We're using the vector from the center of the arc to
|
||||
// an endpoint; so that's normal to the tangent, not
|
||||
// parallel.
|
||||
parallel = !parallel;
|
||||
} else if(e->type == Entity::CUBIC) {
|
||||
if(oth) {
|
||||
dir[i] = e->CubicGetFinishTangentExprs();
|
||||
} else {
|
||||
dir[i] = e->CubicGetStartTangentExprs();
|
||||
}
|
||||
} else {
|
||||
oops();
|
||||
}
|
||||
}
|
||||
if(parallel) {
|
||||
EntityBase *w = SK.GetEntity(workplane);
|
||||
ExprVector wn = w->Normal()->NormalExprsN();
|
||||
AddEq(l, ((dir[0]).Cross(dir[1])).Dot(wn), 0);
|
||||
} else {
|
||||
AddEq(l, (dir[0]).Dot(dir[1]), 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PARALLEL: {
|
||||
EntityBase *ea = SK.GetEntity(entityA), *eb = SK.GetEntity(entityB);
|
||||
if(eb->group.v != group.v) {
|
||||
|
|
|
@ -698,6 +698,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
break;
|
||||
}
|
||||
|
||||
case CURVE_CURVE_TANGENT:
|
||||
case CUBIC_LINE_TANGENT:
|
||||
case ARC_LINE_TANGENT: {
|
||||
Vector textAt, u, v;
|
||||
|
@ -712,7 +713,7 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
textAt = p.Plus(r.WithMagnitude(14/SS.GW.scale));
|
||||
u = norm->NormalU();
|
||||
v = norm->NormalV();
|
||||
} else {
|
||||
} else if(type == CUBIC_LINE_TANGENT) {
|
||||
Vector n;
|
||||
if(workplane.v == Entity::FREE_IN_3D.v) {
|
||||
u = gr;
|
||||
|
@ -731,6 +732,37 @@ void Constraint::DrawOrGetDistance(Vector *labelPos) {
|
|||
Vector dir = SK.GetEntity(entityB)->VectorGetNum();
|
||||
Vector out = n.Cross(dir);
|
||||
textAt = p.Plus(out.WithMagnitude(14/SS.GW.scale));
|
||||
} else {
|
||||
Vector n, dir;
|
||||
EntityBase *wn = SK.GetEntity(workplane)->Normal();
|
||||
u = wn->NormalU();
|
||||
v = wn->NormalV();
|
||||
n = wn->NormalN();
|
||||
EntityBase *eA = SK.GetEntity(entityA);
|
||||
// Big pain; we have to get a vector tangent to the curve
|
||||
// at the shared point, which could be from either a cubic
|
||||
// or an arc.
|
||||
if(other) {
|
||||
textAt = eA->EndpointFinish();
|
||||
if(eA->type == Entity::CUBIC) {
|
||||
dir = eA->CubicGetFinishTangentNum();
|
||||
} else {
|
||||
dir = SK.GetEntity(eA->point[0])->PointGetNum().Minus(
|
||||
SK.GetEntity(eA->point[2])->PointGetNum());
|
||||
dir = n.Cross(dir);
|
||||
}
|
||||
} else {
|
||||
textAt = eA->EndpointStart();
|
||||
if(eA->type == Entity::CUBIC) {
|
||||
dir = eA->CubicGetStartTangentNum();
|
||||
} else {
|
||||
dir = SK.GetEntity(eA->point[0])->PointGetNum().Minus(
|
||||
SK.GetEntity(eA->point[1])->PointGetNum());
|
||||
dir = n.Cross(dir);
|
||||
}
|
||||
}
|
||||
dir = n.Cross(dir);
|
||||
textAt = textAt.Plus(dir.WithMagnitude(14/SS.GW.scale));
|
||||
}
|
||||
|
||||
if(dogd.drawing) {
|
||||
|
|
10
entity.cpp
10
entity.cpp
|
@ -130,6 +130,16 @@ ExprVector EntityBase::CubicGetFinishTangentExprs(void) {
|
|||
poff = SK.GetEntity(point[2+extraPoints])->PointGetExprs();
|
||||
return (pon.Minus(poff));
|
||||
}
|
||||
Vector EntityBase::CubicGetStartTangentNum(void) {
|
||||
Vector pon = SK.GetEntity(point[0])->PointGetNum(),
|
||||
poff = SK.GetEntity(point[1])->PointGetNum();
|
||||
return (pon.Minus(poff));
|
||||
}
|
||||
Vector EntityBase::CubicGetFinishTangentNum(void) {
|
||||
Vector pon = SK.GetEntity(point[3+extraPoints])->PointGetNum(),
|
||||
poff = SK.GetEntity(point[2+extraPoints])->PointGetNum();
|
||||
return (pon.Minus(poff));
|
||||
}
|
||||
|
||||
bool EntityBase::IsWorkplane(void) {
|
||||
return (type == WORKPLANE);
|
||||
|
|
|
@ -414,9 +414,26 @@ SLVS_C_ARC_LINE_TANGENT**
|
|||
|
||||
SLVS_C_CUBIC_LINE_TANGENT*
|
||||
|
||||
The cubic entityA is tangent to the line entityB. If other is false,
|
||||
then the cubic is tangent at its beginning (point[0]). If other is
|
||||
true, then the arc is tangent at its end (point[3]).
|
||||
The cubic entityA is tangent to the line entityB. The variable
|
||||
other indicates:
|
||||
|
||||
if false: the cubic is tangent at its beginning
|
||||
if true: the cubic is tangent at its end
|
||||
|
||||
The beginning of the cubic is point[0], and the end is point[3].
|
||||
|
||||
SLVS_C_CURVE_CURVE_TANGENT**
|
||||
|
||||
The two entities entityA and entityB are tangent. These entities can
|
||||
each be either an arc or a cubic, in any combination. The flags
|
||||
other and other2 indicate which endpoint of the curve is tangent,
|
||||
for entityA and entityB respectively:
|
||||
|
||||
if false: the entity is tangent at its beginning
|
||||
if true: the entity is tangent at its end
|
||||
|
||||
For cubics, point[0] is the beginning, and point[3] is the end. For
|
||||
arcs, point[1] is the beginning, and point[2] is the end.
|
||||
|
||||
SLVS_C_EQUAL_RADIUS
|
||||
|
||||
|
|
|
@ -166,6 +166,7 @@ case SLVS_C_CUBIC_LINE_TANGENT: t = Constraint::CUBIC_LINE_TANGENT; break;
|
|||
case SLVS_C_EQUAL_RADIUS: t = Constraint::EQUAL_RADIUS; break;
|
||||
case SLVS_C_PROJ_PT_DISTANCE: t = Constraint::PROJ_PT_DISTANCE; break;
|
||||
case SLVS_C_WHERE_DRAGGED: t = Constraint::WHERE_DRAGGED; break;
|
||||
case SLVS_C_CURVE_CURVE_TANGENT:t = Constraint::CURVE_CURVE_TANGENT; break;
|
||||
|
||||
default: dbp("bad constraint type %d", sc->type); return;
|
||||
}
|
||||
|
@ -183,6 +184,7 @@ default: dbp("bad constraint type %d", sc->type); return;
|
|||
c.entityC.v = sc->entityC;
|
||||
c.entityD.v = sc->entityD;
|
||||
c.other = (sc->other) ? true : false;
|
||||
c.other2 = (sc->other2) ? true : false;
|
||||
|
||||
SK.constraint.Add(&c);
|
||||
}
|
||||
|
|
|
@ -100,6 +100,7 @@ typedef struct {
|
|||
#define SLVS_C_EQUAL_RADIUS 100029
|
||||
#define SLVS_C_PROJ_PT_DISTANCE 100030
|
||||
#define SLVS_C_WHERE_DRAGGED 100031
|
||||
#define SLVS_C_CURVE_CURVE_TANGENT 100032
|
||||
|
||||
typedef struct {
|
||||
Slvs_hConstraint h;
|
||||
|
@ -118,6 +119,7 @@ typedef struct {
|
|||
Slvs_hEntity entityD;
|
||||
|
||||
int other;
|
||||
int other2;
|
||||
} Slvs_Constraint;
|
||||
|
||||
|
||||
|
|
1
file.cpp
1
file.cpp
|
@ -171,6 +171,7 @@ const SolveSpace::SaveTable SolveSpace::SAVED[] = {
|
|||
{ 'c', "Constraint.entityC.v", 'x', &(SS.sv.c.entityC.v) },
|
||||
{ 'c', "Constraint.entityD.v", 'x', &(SS.sv.c.entityD.v) },
|
||||
{ 'c', "Constraint.other", 'b', &(SS.sv.c.other) },
|
||||
{ 'c', "Constraint.other2", 'b', &(SS.sv.c.other2) },
|
||||
{ 'c', "Constraint.reference", 'b', &(SS.sv.c.reference) },
|
||||
{ 'c', "Constraint.comment", 'N', &(SS.sv.c.comment) },
|
||||
{ 'c', "Constraint.disp.offset.x", 'f', &(SS.sv.c.disp.offset.x) },
|
||||
|
|
4
sketch.h
4
sketch.h
|
@ -399,6 +399,8 @@ public:
|
|||
Vector CubicGetFinishNum(void);
|
||||
ExprVector CubicGetStartTangentExprs(void);
|
||||
ExprVector CubicGetFinishTangentExprs(void);
|
||||
Vector CubicGetStartTangentNum(void);
|
||||
Vector CubicGetFinishTangentNum(void);
|
||||
|
||||
bool HasEndpoints(void);
|
||||
Vector EndpointStart();
|
||||
|
@ -539,6 +541,7 @@ public:
|
|||
static const int PERPENDICULAR = 122;
|
||||
static const int ARC_LINE_TANGENT = 123;
|
||||
static const int CUBIC_LINE_TANGENT = 124;
|
||||
static const int CURVE_CURVE_TANGENT = 125;
|
||||
static const int EQUAL_RADIUS = 130;
|
||||
static const int WHERE_DRAGGED = 200;
|
||||
|
||||
|
@ -558,6 +561,7 @@ public:
|
|||
hEntity entityC;
|
||||
hEntity entityD;
|
||||
bool other;
|
||||
bool other2;
|
||||
|
||||
bool reference; // a ref dimension, that generates no eqs
|
||||
NameStr comment; // since comments are represented as constraints
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
fix bug with rotation in plane where green line stays displayed
|
||||
more tangencies, and rounding (of requests, not parametric)
|
||||
rounding (of requests, not parametric)
|
||||
|
||||
-----
|
||||
rounding, as a special group
|
||||
|
|
Loading…
Reference in New Issue