Skip to content

Commit

Permalink
Allow tangent on arcs/lines/splines without coincident endpoints.
Browse files Browse the repository at this point in the history
  • Loading branch information
ruevs committed Nov 7, 2024
1 parent dedc6d4 commit d97b9be
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 19 deletions.
97 changes: 81 additions & 16 deletions src/constraint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,8 @@ hConstraint Constraint::ConstrainCoincident(hEntity ptA, hEntity ptB) {
Entity::NO_ENTITY, Entity::NO_ENTITY, /*other=*/false, /*other2=*/false);
}

bool Constraint::ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc) {
bool Constraint::ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc,
Entity *arcendpoint) {
Vector l0 = SK.GetEntity(line->point[0])->PointGetNum(),
l1 = SK.GetEntity(line->point[1])->PointGetNum();
Vector a1 = SK.GetEntity(arc->point[1])->PointGetNum(),
Expand All @@ -140,16 +141,32 @@ bool Constraint::ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *ar
c->other = false;
} else if(l0.Equals(a2) || l1.Equals(a2)) {
c->other = true;
} else if(nullptr != arcendpoint) {
Vector p = arcendpoint->PointGetNum();
if(a1.Equals(p)) {
c->other = false;
} else if(a2.Equals(p)) {
c->other = true;
} else {
Error(_("The point you selected does not belong to the arc. "
"The arc and line segment do not share an end point.\n\n"
"Select the end point of the arc at which you want "
"it to be tangent to the line."));
return false;
}
} else {
Error(_("The tangent arc and line segment must share an "
"endpoint. Constrain them with Constrain -> "
"On Point before constraining tangent."));
"On Point before constraining tangent.\n\n"
"Alternatively select the end point of the arc "
"at which you want it to be tangent to the line."));
return false;
}
return true;
}

bool Constraint::ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic) {
bool Constraint::ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic,
Entity *curveendpoint) {
Vector l0 = SK.GetEntity(line->point[0])->PointGetNum(),
l1 = SK.GetEntity(line->point[1])->PointGetNum();
Vector as = cubic->CubicGetStartNum(),
Expand All @@ -159,16 +176,32 @@ bool Constraint::ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *
c->other = false;
} else if(l0.Equals(af) || l1.Equals(af)) {
c->other = true;
} else if(nullptr != curveendpoint) {
Vector p = curveendpoint->PointGetNum();
if(as.Equals(p)) {
c->other = false;
} else if(af.Equals(p)) {
c->other = true;
} else {
Error(_("The point you selected is not an end point of the cubic spline. "
"The spline and line segment do not share an end point.\n\n"
"Select the end point of the spline at which you want "
"it to be tangent to the line."));
return false;
}
} else {
Error(_("The tangent cubic and line segment must share an "
Error(_("The tangent cubic spline and line segment must share an "
"endpoint. Constrain them with Constrain -> "
"On Point before constraining tangent."));
"On Point before constraining tangent.\n\n"
"Alternatively select the end point of the cubic spline "
"at which you want it to be tangent to the line."));
return false;
}
return true;
}

bool Constraint::ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB) {
bool Constraint::ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB, Entity *epA,
Entity *epB) {
Vector as = eA->EndpointStart(),
af = eA->EndpointFinish(),
bs = eB->EndpointStart(),
Expand All @@ -185,11 +218,35 @@ bool Constraint::ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *e
} else if(af.Equals(bf)) {
c->other = true;
c->other2 = true;
} else if((nullptr != epA) && (nullptr != epB)) {
Vector pa = epA->PointGetNum(),
pb = epB->PointGetNum();
if((as.Equals(pa) && bs.Equals(pb)) || (as.Equals(pb) && bs.Equals(pa))) {
c->other = false;
c->other2 = false;
} else if((as.Equals(pa) && bf.Equals(pb)) || (as.Equals(pb) && bf.Equals(pa))) {
c->other = false;
c->other2 = true;
} else if((af.Equals(pa) && bs.Equals(pb)) || (af.Equals(pb) && bs.Equals(pa))) {
c->other = true;
c->other2 = false;
} else if((af.Equals(pa) && bf.Equals(pb)) || (af.Equals(pb) && bf.Equals(pa))) {
c->other = true;
c->other2 = true;
} else {
Error(_("The points you selected are not end points of the two curves. "
"The curves do not share an end point.\n\n"
"Select the end points of both curves at which you want "
"them to be tangent to each other."));
return false;
}
} else {
Error(_("The curves must share an endpoint. Constrain them "
"with Constrain -> On Point before constraining "
"tangent."));
return false;
"tangent.\n\n"
"Alternatively select the end points of both "
"curves at which you want the curves to be tangent."));
return false;
}
return true;
}
Expand Down Expand Up @@ -780,40 +837,46 @@ void Constraint::MenuConstrain(Command id) {
c.entityB = gs.vector[k];
newcons.push_back(c);
}
} else if(gs.lineSegments == 1 && gs.arcs == 1 && gs.n == 2) {
} else if(gs.lineSegments == 1 && gs.arcs == 1 &&
(gs.n == 2 || (gs.points == 1 && gs.n == 3))) {
Entity *line = SK.GetEntity(gs.entity[0]),
*arc = SK.GetEntity(gs.entity[1]);
if(line->type == Entity::Type::ARC_OF_CIRCLE) {
swap(line, arc);
}
if(!ConstrainArcLineTangent(&c, line, arc)) {
if(!ConstrainArcLineTangent(
&c, line, arc, (1 == gs.points) ? SK.GetEntity(gs.point[0]) : nullptr)) {
return;
}
c.type = Type::ARC_LINE_TANGENT;
c.entityA = arc->h;
c.entityB = line->h;
newcons.push_back(c);
} else if(gs.lineSegments == 1 && gs.cubics == 1 && gs.n == 2) {
} else if(gs.lineSegments == 1 && gs.cubics == 1 &&
(gs.n == 2 || (gs.points == 1 && gs.n == 3))) {
Entity *line = SK.GetEntity(gs.entity[0]),
*cubic = SK.GetEntity(gs.entity[1]);
if(line->type == Entity::Type::CUBIC) {
swap(line, cubic);
}
if(!ConstrainCubicLineTangent(&c, line, cubic)) {
if(!ConstrainCubicLineTangent(
&c, line, cubic, (1 == gs.points) ? SK.GetEntity(gs.point[0]) : nullptr)) {
return;
}
c.type = Type::CUBIC_LINE_TANGENT;
c.entityA = cubic->h;
c.entityB = line->h;
newcons.push_back(c);
} else if(gs.cubics + gs.arcs == 2 && gs.n == 2) {
} else if(gs.cubics + gs.arcs == 2 && (gs.n == 2 || (gs.points == 2 && gs.n == 4))) {
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]);
if(!ConstrainCurveCurveTangent(&c, eA, eB)) {
if(!ConstrainCurveCurveTangent(
&c, eA, eB, (2 == gs.points) ? SK.GetEntity(gs.point[0]) : nullptr,
(2 == gs.points) ? SK.GetEntity(gs.point[1]) : nullptr)) {
return;
}
c.type = Type::CURVE_CURVE_TANGENT;
Expand All @@ -828,8 +891,10 @@ void Constraint::MenuConstrain(Command id) {
" * one or more line segments and one or more normals (parallel)\n"
" * two or more normals (parallel)\n"
" * two line segments, arcs, or beziers, that share "
"an endpoint (tangent)\n"));
return;
"an endpoint (tangent)\n"
" * two line segments, arcs, or beziers, that do not share "
"an endpoint and the end point(s) of the curve(s) (tangent)\n"));
return;
}
SS.UndoRemember();
for (auto&& nc:newcons)
Expand Down
9 changes: 6 additions & 3 deletions src/sketch.h
Original file line number Diff line number Diff line change
Expand Up @@ -806,9 +806,12 @@ class Constraint : public ConstraintBase {
static hConstraint TryConstrain(Constraint::Type type, hEntity ptA, hEntity ptB,
hEntity entityA, hEntity entityB = Entity::NO_ENTITY,
bool other = false, bool other2 = false);
static bool ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc);
static bool ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic);
static bool ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB);
static bool ConstrainArcLineTangent(Constraint *c, Entity *line, Entity *arc,
Entity *arcendpoint);
static bool ConstrainCubicLineTangent(Constraint *c, Entity *line, Entity *cubic,
Entity *curveendpoint);
static bool ConstrainCurveCurveTangent(Constraint *c, Entity *eA, Entity *eB, Entity *p1,
Entity *p2);
};

class hEquation {
Expand Down

0 comments on commit d97b9be

Please sign in to comment.