Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions src/clipboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,28 +258,31 @@ void GraphicsWindow::PasteClipboard(Vector trans, double theta, double scale) {
c.valA *= fabs(scale);
break;
case Constraint::Type::ARC_LINE_TANGENT: {
Entity *line = SK.GetEntity(c.entityB),
*arc = SK.GetEntity(c.entityA);
if(line->type == Entity::Type::ARC_OF_CIRCLE) {
swap(line, arc);
if(scale < 0) {
// When mirroring swap the end point of the arc. The reason is that arcs are
// defined as counter-clockwise from the start point to the end point. And we
// swapped its points in mapPoint above to avoid inverting it.
c.other = !c.other;
}
Constraint::ConstrainArcLineTangent(&c, line, arc);
break;
}
case Constraint::Type::CUBIC_LINE_TANGENT: {
Entity *line = SK.GetEntity(c.entityB),
*cubic = SK.GetEntity(c.entityA);
if(line->type == Entity::Type::CUBIC) {
swap(line, cubic);
}
Constraint::ConstrainCubicLineTangent(&c, line, cubic);
// Nothing to do for CUBIC unlike the ARC_OF_CIRCLE above and below.
break;
}
case Constraint::Type::CURVE_CURVE_TANGENT: {
Entity *eA = SK.GetEntity(c.entityA),
*eB = SK.GetEntity(c.entityB);
Constraint::ConstrainCurveCurveTangent(&c, eA, eB);
break;
if(scale < 0) {
// When mirroring swap the end points of arcs. The reason is that arcs are
// defined as counter-clockwise from the start point to the end point. And we
// swapped their points in mapPoint above to avoid inverting them.
// CUBIC splines do not need this.
if(EntityBase::Type::ARC_OF_CIRCLE == SK.GetEntity(c.entityA)->type) {
c.other = !c.other;
}
if(EntityBase::Type::ARC_OF_CIRCLE == SK.GetEntity(c.entityB)->type) {
c.other2 = !c.other2;
}
}
}
case Constraint::Type::HORIZONTAL:
case Constraint::Type::VERTICAL:
Expand Down
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