diff --git a/src/Mod/Sketcher/App/Sketch.cpp b/src/Mod/Sketcher/App/Sketch.cpp index 35f6bdb64..974ea38bc 100644 --- a/src/Mod/Sketcher/App/Sketch.cpp +++ b/src/Mod/Sketcher/App/Sketch.cpp @@ -836,8 +836,33 @@ int Sketch::addTangentConstraint(int geoId1, int geoId2) GCSsys.addConstraintTangent(l, c, tag); return ConstraintsCounter; } - } else - Base::Console().Warning("Tangency constraints between circles and arcs are not implemented yet.\n"); + } else if (Geoms[geoId1].type == Circle) { + GCS::Circle &c = Circles[Geoms[geoId1].index]; + if (Geoms[geoId2].type == Circle) { + GCS::Circle &c2 = Circles[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(c, c2, tag); + return ConstraintsCounter; + } else if (Geoms[geoId2].type == Arc) { + GCS::Arc &a = Arcs[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(c, a, tag); + return ConstraintsCounter; + } + } else if (Geoms[geoId1].type == Arc) { + GCS::Arc &a = Arcs[Geoms[geoId1].index]; + if (Geoms[geoId2].type == Circle) { + GCS::Circle &c = Circles[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(c, a, tag); + return ConstraintsCounter; + } else if (Geoms[geoId2].type == Arc) { + GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangent(a, a2, tag); + return ConstraintsCounter; + } + } return -1; } @@ -850,8 +875,8 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2) // 2) Line1, start/end/mid, Circle2 // 3) Line1, start/end/mid, Arc2 // 4) Arc1, start/end, Line2 - // 5) Arc1, start/end, Circle2 (not implemented yet) - // 6) Arc1, start/end, Arc2 (not implemented yet) + // 5) Arc1, start/end, Circle2 + // 6) Arc1, start/end, Arc2 geoId1 = checkGeoId(geoId1); geoId2 = checkGeoId(geoId2); @@ -895,16 +920,24 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2) return ConstraintsCounter; } else if (Geoms[geoId2].type == Arc) { - //GCS::Arcs &a2 = Arcs[Geoms[geoId2].index]; - //GCSsys.addConstraintPointOnArc(p1, a2); - //GCSsys.addConstraintTangent(a1, a2); - Base::Console().Warning("Tangency constraints between circles and arcs are not implemented yet.\n"); + GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; + int tag = ++ConstraintsCounter; + GCSsys.addConstraintPointOnArc(p1, a2, tag); + GCSsys.addConstraintTangent(a1, a2, tag); + return ConstraintsCounter; } else if (Geoms[geoId2].type == Circle) { - //GCS::Circle &c2 = Circles[Geoms[geoId2].index]; - //GCSsys.addConstraintPointOnCircle(p1, c2); - //GCSsys.addConstraintTangent(a1, c2); - Base::Console().Warning("Tangency constraints between circles and arcs are not implemented yet.\n"); + GCS::Circle &c2 = Circles[Geoms[geoId2].index]; + if (pos1 == start) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangentCircle2Arc(c2, a1, tag); + return ConstraintsCounter; + } + else if (pos1 == end) { + int tag = ++ConstraintsCounter; + GCSsys.addConstraintTangentArc2Circle(a1, c2, tag); + return ConstraintsCounter; + } } } return -1; @@ -917,7 +950,7 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos // 1) Line1, start/end/mid, Line2, start/end/mid // 2) Line1, start/end/mid, Arc2, start/end // 3) Arc1, start/end, Line2, start/end/mid (converted to case #2) - // 4) Arc1, start/end, Arc2, start/end (not implemented yet) + // 4) Arc1, start/end, Arc2, start/end geoId1 = checkGeoId(geoId1); geoId2 = checkGeoId(geoId2); @@ -970,7 +1003,7 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos GCSsys.addConstraintTangentLine2Arc(l1.p1, l1.p2, a2, tag); return ConstraintsCounter; } - else if (pos1 == mid) { + else if (pos1 == mid) { // FIXME: coincidence with midpoint of line?? int tag = ++ConstraintsCounter; GCSsys.addConstraintP2PCoincident(p1, p2, tag); GCSsys.addConstraintTangent(l1, a2, tag); @@ -988,7 +1021,7 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos GCSsys.addConstraintTangentArc2Line(a2, l1.p2, l1.p1, tag); return ConstraintsCounter; } - else if (pos1 == mid) { + else if (pos1 == mid) { // FIXME: coincidence with midpoint of line?? int tag = ++ConstraintsCounter; GCSsys.addConstraintP2PCoincident(p1, p2, tag); GCSsys.addConstraintTangent(l1, a2, tag); @@ -1000,12 +1033,26 @@ int Sketch::addTangentConstraint(int geoId1, PointPos pos1, int geoId2, PointPos } } else if (Geoms[geoId1].type == Arc) { - //GCS::Arc &a1 = Arcs[Geoms[geoId1].index]; + GCS::Arc &a1 = Arcs[Geoms[geoId1].index]; if (Geoms[geoId2].type == Arc) { - //GCS::Arcs &a2 = Arcs[Geoms[geoId2].index]; - //GCSsys.addConstraintPointOnArc(p1, a2); - //GCSsys.addConstraintTangent(a1, a2); - Base::Console().Warning("Tangency constraints between arcs are not implemented yet.\n"); + GCS::Arc &a2 = Arcs[Geoms[geoId2].index]; + if (pos1 == start && (pos2 == start || pos2 == end)) { + int tag = ++ConstraintsCounter; + if (pos2 == start) + GCSsys.addConstraintTangentArc2Arc(a1, true, a2, false, tag); + else // if (pos2 == end) + GCSsys.addConstraintTangentArc2Arc(a1, true, a2, true, tag); + // GCSsys.addConstraintTangentArc2Arc(a2, false, a1, false, tag); + return ConstraintsCounter; + } + else if (pos1 == end && (pos2 == start || pos2 == end)) { + int tag = ++ConstraintsCounter; + if (pos2 == start) + GCSsys.addConstraintTangentArc2Arc(a1, false, a2, false, tag); + else // if (pos2 == end) + GCSsys.addConstraintTangentArc2Arc(a1, false, a2, true, tag); + return ConstraintsCounter; + } } } return -1; diff --git a/src/Mod/Sketcher/App/freegcs/Constraints.cpp b/src/Mod/Sketcher/App/freegcs/Constraints.cpp index b893bb70e..76b42f8d7 100644 --- a/src/Mod/Sketcher/App/freegcs/Constraints.cpp +++ b/src/Mod/Sketcher/App/freegcs/Constraints.cpp @@ -771,4 +771,64 @@ double ConstraintMidpointOnLine::grad(double *param) return scale * deriv; } +// TangentCircumf +ConstraintTangentCircumf::ConstraintTangentCircumf(Point &p1, Point &p2, + double *rad1, double *rad2, bool internal_) +{ + internal = internal_; + pvec.push_back(p1.x); + pvec.push_back(p1.y); + pvec.push_back(p2.x); + pvec.push_back(p2.y); + pvec.push_back(rad1); + pvec.push_back(rad2); + origpvec = pvec; + rescale(); +} + +ConstraintType ConstraintTangentCircumf::getTypeId() +{ + return TangentCircumf; +} + +void ConstraintTangentCircumf::rescale(double coef) +{ + scale = coef * 1; +} + +double ConstraintTangentCircumf::error() +{ + double dx = (*c1x() - *c2x()); + double dy = (*c1y() - *c2y()); + if (internal) + return scale * (sqrt(dx*dx + dy*dy) - std::abs(*r1() - *r2())); + else + return scale * (sqrt(dx*dx + dy*dy) - (*r1() + *r2())); +} + +double ConstraintTangentCircumf::grad(double *param) +{ + double deriv=0.; + if (param == c1x() || param == c1y() || + param == c2x() || param == c2y()|| + param == r1() || param == r2()) { + double dx = (*c1x() - *c2x()); + double dy = (*c1y() - *c2y()); + double d = sqrt(dx*dx + dy*dy); + if (param == c1x()) deriv += dx/d; + if (param == c1y()) deriv += dy/d; + if (param == c2x()) deriv += -dx/d; + if (param == c2y()) deriv += -dy/d; + if (internal) { + if (param == r1()) deriv += (*r1() > *r2()) ? -1 : 1; + if (param == r2()) deriv += (*r1() > *r2()) ? 1 : -1; + } + else { + if (param == r1()) deriv += -1; + if (param == r2()) deriv += -1; + } + } + return scale * deriv; +} + } //namespace GCS diff --git a/src/Mod/Sketcher/App/freegcs/Constraints.h b/src/Mod/Sketcher/App/freegcs/Constraints.h index 40018a9e8..6a9369ab2 100644 --- a/src/Mod/Sketcher/App/freegcs/Constraints.h +++ b/src/Mod/Sketcher/App/freegcs/Constraints.h @@ -44,7 +44,8 @@ namespace GCS Parallel = 7, Perpendicular = 8, L2LAngle = 9, - MidpointOnLine = 10 + MidpointOnLine = 10, + TangentCircumf = 11 }; class Constraint @@ -262,6 +263,26 @@ namespace GCS virtual double grad(double *); }; + // TangentCircumf + class ConstraintTangentCircumf : public Constraint + { + private: + inline double* c1x() { return pvec[0]; } + inline double* c1y() { return pvec[1]; } + inline double* c2x() { return pvec[2]; } + inline double* c2y() { return pvec[3]; } + inline double* r1() { return pvec[4]; } + inline double* r2() { return pvec[5]; } + bool internal; + public: + ConstraintTangentCircumf(Point &p1, Point &p2, + double *rad1, double *rad2, bool internal_=false); + virtual ConstraintType getTypeId(); + virtual void rescale(double coef=1.); + virtual double error(); + virtual double grad(double *); + }; + } //namespace GCS #endif // FREEGCS_CONSTRAINTS_H diff --git a/src/Mod/Sketcher/App/freegcs/GCS.cpp b/src/Mod/Sketcher/App/freegcs/GCS.cpp index 069e18162..2d7c0eba3 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.cpp +++ b/src/Mod/Sketcher/App/freegcs/GCS.cpp @@ -286,6 +286,14 @@ int System::addConstraintMidpointOnLine(Point &l1p1, Point &l1p2, return addConstraint(constr); } +int System::addConstraintTangentCircumf(Point &p1, Point &p2, double *rad1, double *rad2, + bool internal, int tagId) +{ + Constraint *constr = new ConstraintTangentCircumf(p1, p2, rad1, rad2, internal); + constr->setTag(tagId); + return addConstraint(constr); +} + // derived constraints int System::addConstraintP2PCoincident(Point &p1, Point &p2, int tagId) @@ -352,6 +360,33 @@ int System::addConstraintTangent(Line &l, Arc &a, int tagId) return addConstraintP2LDistance(a.center, l, a.rad, tagId); } +int System::addConstraintTangent(Circle &c1, Circle &c2, int tagId) +{ + double dx = *(c2.center.x) - *(c1.center.x); + double dy = *(c2.center.y) - *(c1.center.y); + double d = sqrt(dx*dx + dy*dy); + return addConstraintTangentCircumf(c1.center, c2.center, c1.rad, c2.rad, + (d < *c1.rad || d < *c2.rad), tagId); +} + +int System::addConstraintTangent(Arc &a1, Arc &a2, int tagId) +{ + double dx = *(a2.center.x) - *(a1.center.x); + double dy = *(a2.center.y) - *(a1.center.y); + double d = sqrt(dx*dx + dy*dy); + return addConstraintTangentCircumf(a1.center, a2.center, a1.rad, a2.rad, + (d < *a1.rad || d < *a2.rad), tagId); +} + +int System::addConstraintTangent(Circle &c, Arc &a, int tagId) +{ + double dx = *(a.center.x) - *(c.center.x); + double dy = *(a.center.y) - *(c.center.y); + double d = sqrt(dx*dx + dy*dy); + return addConstraintTangentCircumf(c.center, a.center, c.rad, a.rad, + (d < *c.rad || d < *a.rad), tagId); +} + int System::addConstraintTangentLine2Arc(Point &p1, Point &p2, Arc &a, int tagId) { addConstraintP2PCoincident(p2, a.start, tagId); @@ -366,6 +401,43 @@ int System::addConstraintTangentArc2Line(Arc &a, Point &p1, Point &p2, int tagId return addConstraintP2PAngle(p1, p2, a.endAngle, incr_angle, tagId); } +int System::addConstraintTangentCircle2Arc(Circle &c, Arc &a, int tagId) +{ + addConstraintPointOnCircle(a.start, c, tagId); + double dx = *(a.start.x) - *(c.center.x); + double dy = *(a.start.y) - *(c.center.y); + if (dx * cos(*(a.startAngle)) + dy * sin(*(a.startAngle)) > 0) + addConstraintP2PAngle(c.center, a.start, a.startAngle, 0, tagId); + else + addConstraintP2PAngle(c.center, a.start, a.startAngle, M_PI, tagId); +} + +int System::addConstraintTangentArc2Circle(Arc &a, Circle &c, int tagId) +{ + addConstraintPointOnCircle(a.end, c, tagId); + double dx = *(a.end.x) - *(c.center.x); + double dy = *(a.end.y) - *(c.center.y); + if (dx * cos(*(a.endAngle)) + dy * sin(*(a.endAngle)) > 0) + addConstraintP2PAngle(c.center, a.end, a.endAngle, 0, tagId); + else + addConstraintP2PAngle(c.center, a.end, a.endAngle, M_PI, tagId); +} + +int System::addConstraintTangentArc2Arc(Arc &a1, bool reverse1, Arc &a2, bool reverse2, + int tagId) +{ + Point &p1 = reverse1 ? a1.start : a1.end; + Point &p2 = reverse2 ? a2.end : a2.start; + addConstraintP2PCoincident(p1, p2, tagId); + + double *angle1 = reverse1 ? a1.startAngle : a1.endAngle; + double *angle2 = reverse2 ? a2.endAngle : a2.startAngle; + if (cos(*angle1) * cos(*angle2) + sin(*angle1) * sin(*angle2) > 0) + addConstraintEqual(angle1, angle2, tagId); + else + addConstraintP2PAngle(p2, a2.center, angle1, 0, tagId); +} + int System::addConstraintCircleRadius(Circle &c, double *radius, int tagId) { return addConstraintEqual(c.rad, radius, tagId); diff --git a/src/Mod/Sketcher/App/freegcs/GCS.h b/src/Mod/Sketcher/App/freegcs/GCS.h index 9e809c6c2..3c8538348 100644 --- a/src/Mod/Sketcher/App/freegcs/GCS.h +++ b/src/Mod/Sketcher/App/freegcs/GCS.h @@ -101,6 +101,8 @@ namespace GCS int addConstraintMidpointOnLine(Line &l1, Line &l2, int tagId=0); int addConstraintMidpointOnLine(Point &l1p1, Point &l1p2, Point &l2p1, Point &l2p2, int tagId=0); + int addConstraintTangentCircumf(Point &p1, Point &p2, double *rad1, double *rad2, + bool internal=false, int tagId=0); // derived constraints int addConstraintP2PCoincident(Point &p1, Point &p2, int tagId=0); @@ -115,8 +117,15 @@ namespace GCS int addConstraintPointOnArc(Point &p, Arc &a, int tagId=0); int addConstraintTangent(Line &l, Circle &c, int tagId=0); int addConstraintTangent(Line &l, Arc &a, int tagId=0); + int addConstraintTangent(Circle &c1, Circle &c2, int tagId=0); + int addConstraintTangent(Arc &a1, Arc &a2, int tagId=0); + int addConstraintTangent(Circle &c, Arc &a, int tagId=0); int addConstraintTangentLine2Arc(Point &p1, Point &p2, Arc &a, int tagId=0); int addConstraintTangentArc2Line(Arc &a, Point &p1, Point &p2, int tagId=0); + int addConstraintTangentCircle2Arc(Circle &c, Arc &a, int tagId=0); + int addConstraintTangentArc2Circle(Arc &a, Circle &c, int tagId=0); + int addConstraintTangentArc2Arc(Arc &a1, bool reverse1, Arc &a2, bool reverse2, + int tagId=0); int addConstraintCircleRadius(Circle &c, double *radius, int tagId=0); int addConstraintArcRadius(Arc &a, double *radius, int tagId=0); int addConstraintEqualLength(Line &l1, Line &l2, double *length, int tagId=0); diff --git a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp index 8699b4a1d..7dc3273ab 100644 --- a/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp +++ b/src/Mod/Sketcher/Gui/ViewProviderSketch.cpp @@ -2153,24 +2153,31 @@ Restart: const Part::GeomCircle *circle1 = dynamic_cast(geo1); const Part::GeomCircle *circle2 = dynamic_cast(geo2); // tangency between two cicles + Base::Vector3d dir = (circle2->getCenter() - circle1->getCenter()).Normalize(); + pos = circle1->getCenter() + dir * circle1->getRadius(); + relPos = dir * 1; } else if (geo2->getTypeId()== Part::GeomCircle::getClassTypeId()) { std::swap(geo1,geo2); } - if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId()) { + if (geo1->getTypeId()== Part::GeomCircle::getClassTypeId() && + geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomCircle *circle = dynamic_cast(geo1); - if (geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { - const Part::GeomArcOfCircle *arc = dynamic_cast(geo2); - // tangency between a circle and an arc - } + const Part::GeomArcOfCircle *arc = dynamic_cast(geo2); + // tangency between a circle and an arc + Base::Vector3d dir = (arc->getCenter() - circle->getCenter()).Normalize(); + pos = circle->getCenter() + dir * circle->getRadius(); + relPos = dir * 1; } - - if (geo1->getTypeId()== Part::GeomArcOfCircle::getClassTypeId() && - geo1->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { + else if (geo1->getTypeId()== Part::GeomArcOfCircle::getClassTypeId() && + geo2->getTypeId()== Part::GeomArcOfCircle::getClassTypeId()) { const Part::GeomArcOfCircle *arc1 = dynamic_cast(geo1); const Part::GeomArcOfCircle *arc2 = dynamic_cast(geo2); // tangency between two arcs + Base::Vector3d dir = (arc2->getCenter() - arc1->getCenter()).Normalize(); + pos = arc1->getCenter() + dir * arc1->getRadius(); + relPos = dir * 1; } dynamic_cast(sep->getChild(1))->abPos = SbVec3f(pos.x, pos.y, zConstr); //Absolute Reference dynamic_cast(sep->getChild(1))->translation = SbVec3f(relPos.x, relPos.y, 0);