+std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
+{
+ std::set<FeaturePtr> aCoincidences = collectCoincidences(theFeature1, theFeature2);
+ // collect points only
+ std::set<AttributePtr> aCoincidentPoints;
+ std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
+ for (; aCIt != aCoincidences.end(); ++ aCIt) {
+ AttributeRefAttrPtr aRefAttrA = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_A());
+ AttributeRefAttrPtr aRefAttrB = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_B());
+ if (!aRefAttrA || aRefAttrA->isObject() ||
+ !aRefAttrB || aRefAttrB->isObject())
+ continue;
+
+ AttributePtr anAttrA = aRefAttrA->attr();
+ AttributePtr anAttrB = aRefAttrB->attr();
+ if (anAttrA->id() != SketchPlugin_Arc::CENTER_ID() &&
+ anAttrA->id() != SketchPlugin_Circle::CENTER_ID() &&
+ anAttrB->id() != SketchPlugin_Arc::CENTER_ID() &&
+ anAttrB->id() != SketchPlugin_Circle::CENTER_ID()) {
+ aCoincidentPoints.insert(anAttrA);
+ aCoincidentPoints.insert(anAttrB);
+ }
+ }
+ 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) {
+ GCSPointPtr aPoint =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
+
+ adjustAngleBetweenCurves(aCirc1, aCirc2, aPoint, theAngle);
+ aNewConstr =
+ GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*aCirc1, *aCirc2, *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));
+}