+ return aCoincidentPoints;
+}
+
+bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, EntityWrapperPtr theArc2)
+{
+ std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(
+ GCS_EDGE_WRAPPER(theArc1)->entity());
+ std::shared_ptr<GCS::Circle> aCirc2 = std::dynamic_pointer_cast<GCS::Circle>(
+ GCS_EDGE_WRAPPER(theArc2)->entity());
+
+ if (!aCirc1 || !aCirc2)
+ return false;
+
+ double aDX = *(aCirc1->center.x) - *(aCirc2->center.x);
+ double aDY = *(aCirc1->center.y) - *(aCirc2->center.y);
+ double aDist = sqrt(aDX * aDX + aDY * aDY);
+
+ return (aDist < *(aCirc1->rad) || aDist < *(aCirc2->rad));
+}
+
+// sets angle to 0 or 180 degrees
+static void adjustAngleBetweenCurves(const GCSCurvePtr& theCurve1,
+ const GCSCurvePtr& theCurve2,
+ const GCSPointPtr& thePoint,
+ double* theAngle)
+{
+ double anAngle = GCS::System().calculateAngleViaPoint(*theCurve1, *theCurve2, *thePoint);
+ // bring angle to [-pi..pi]
+ if (anAngle > PI) anAngle -= 2.0 * PI;
+ if (anAngle < -PI) anAngle += 2.0 * PI;
+ // set angle value according to the current angle between curves
+ if (fabs(anAngle) <= PI / 2.)
+ *theAngle = 0.0;
+ else
+ *theAngle = PI;
+}
+
+
+ConstraintWrapperPtr createArcLineTangency(EntityWrapperPtr theEntity1,
+ EntityWrapperPtr theEntity2,
+ EntityWrapperPtr theSharedPoint,
+ double* theAngle)
+{
+ EdgeWrapperPtr anEntLine, anEntCirc;
+ if (theEntity1->type() == ENTITY_LINE) {
+ anEntLine = GCS_EDGE_WRAPPER(theEntity1);
+ anEntCirc = GCS_EDGE_WRAPPER(theEntity2);
+ } else {
+ anEntLine = GCS_EDGE_WRAPPER(theEntity2);
+ anEntCirc = GCS_EDGE_WRAPPER(theEntity1);
+ }
+
+ std::shared_ptr<GCS::Circle> aCirc =
+ std::dynamic_pointer_cast<GCS::Circle>(anEntCirc->entity());
+ std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(aCirc);
+
+ std::shared_ptr<GCS::Line> aLine =
+ std::dynamic_pointer_cast<GCS::Line>(anEntLine->entity());
+
+ GCSConstraintPtr aNewConstr;
+ if (theSharedPoint && anArc) { // do not process shared point between circle and line
+ GCSPointPtr aPoint =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
+
+ adjustAngleBetweenCurves(anArc, aLine, aPoint, theAngle);
+ aNewConstr =
+ GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*anArc, *aLine, *aPoint, theAngle));
+ } else {
+ aNewConstr =
+ GCSConstraintPtr(new GCS::ConstraintP2LDistance(aCirc->center, *aLine, aCirc->rad));
+ }
+
+ return ConstraintWrapperPtr(
+ new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CIRCLE_LINE));
+}
+
+ConstraintWrapperPtr createArcArcTangency(EntityWrapperPtr theEntity1,
+ EntityWrapperPtr theEntity2,
+ bool theInternalTangency,
+ EntityWrapperPtr theSharedPoint,
+ double* theAngle)
+{
+ std::shared_ptr<GCS::Circle> aCirc1 =
+ std::dynamic_pointer_cast<GCS::Circle>(GCS_EDGE_WRAPPER(theEntity1)->entity());
+ std::shared_ptr<GCS::Circle> aCirc2 =
+ std::dynamic_pointer_cast<GCS::Circle>(GCS_EDGE_WRAPPER(theEntity2)->entity());
+
+ GCSConstraintPtr aNewConstr;
+ if (theSharedPoint) {
+ std::shared_ptr<GCS::Arc> anArc1 = std::dynamic_pointer_cast<GCS::Arc>(aCirc1);
+ std::shared_ptr<GCS::Arc> anArc2 = std::dynamic_pointer_cast<GCS::Arc>(aCirc2);
+ GCSPointPtr aPoint =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
+
+ adjustAngleBetweenCurves(anArc1, anArc2, aPoint, theAngle);
+ aNewConstr =
+ GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*anArc1, *anArc2, *aPoint, theAngle));
+ } else {
+ aNewConstr = GCSConstraintPtr(new GCS::ConstraintTangentCircumf(aCirc1->center, aCirc2->center,
+ aCirc1->rad, aCirc2->rad, theInternalTangency));
+ }
+
+ return ConstraintWrapperPtr(
+ new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CIRCLE_CIRCLE));