X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FSketchSolver_ConstraintTangent.cpp;h=22516bff36b9ad9ca01c77ba321d0a0d5d864b33;hb=06e7f5859095193fc7f498bd89a7d28009794f53;hp=709d09185bfe2ad3e4fe89ec65b5584d63321c8e;hpb=fe3678a85238df2b57ea18b341003ebef176e287;p=modules%2Fshaper.git diff --git a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp index 709d09185..22516bff3 100644 --- a/src/SketchSolver/SketchSolver_ConstraintTangent.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintTangent.cpp @@ -1,16 +1,46 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D +// Copyright (C) 2014-2023 CEA, EDF +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// #include #include #include #include +#include #include #include +#include +#include #include +#include + +#include + +#include + +#include +#include #include #include +#include +#include #include @@ -26,7 +56,11 @@ static std::set collectCoincidences(FeaturePtr theFeature1, FeatureP /// \brief Check whether the entities has only one shared point or less. /// Return list of coincident points. -static std::list coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2); +static std::set coincidentBoundaryPoints(FeaturePtr theFeature1, + FeaturePtr theFeature2); + +/// \brief Collect points coincident with each of two features +static std::set coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2); /// \brief Check if two connected arcs have centers /// in same direction relatively to connection point @@ -40,11 +74,14 @@ static ConstraintWrapperPtr double* theAngle = 0); static ConstraintWrapperPtr - createArcArcTangency(EntityWrapperPtr theEntity1, - EntityWrapperPtr theEntity2, - bool theInternalTangency, - EntityWrapperPtr theSharedPoint = EntityWrapperPtr(), - double* theAngle = 0); + createCurveCurveTangency(EntityWrapperPtr theEntity1, + EntityWrapperPtr theEntity2, + bool theInternalTangency, + EntityWrapperPtr theSharedPoint = EntityWrapperPtr(), + double* theAngle = 0); + +static void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2, + GCSPointPtr& theTangencyPoint); void SketchSolver_ConstraintTangent::process() @@ -73,12 +110,27 @@ void SketchSolver_ConstraintTangent::rebuild() if (mySolverConstraint) myStorage->removeConstraint(myBaseConstraint); + std::shared_ptr aStorage = + std::dynamic_pointer_cast(myStorage); + mySolverConstraint = ConstraintWrapperPtr(); mySharedPoint = AttributePtr(); + if (myAuxPoint) { + GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint); + if (myAuxParameters[0]) + aParams.insert(myAuxParameters[0]->scalar()); + if (myAuxParameters[1]) + aParams.insert(myAuxParameters[1]->scalar()); + aStorage->removeParameters(aParams); + myAuxPoint = EntityWrapperPtr(); + myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr(); + } // Check the quantity of entities of each type and their order (arcs first) int aNbLines = 0; int aNbCircles = 0; + int aNbEllipses = 0; + int aNbSplines = 0; std::list::iterator anEntIt = myAttributes.begin(); for (; anEntIt != myAttributes.end(); ++anEntIt) { if (!(*anEntIt).get()) @@ -87,17 +139,21 @@ void SketchSolver_ConstraintTangent::rebuild() ++aNbLines; else if ((*anEntIt)->type() == ENTITY_ARC || (*anEntIt)->type() == ENTITY_CIRCLE) ++aNbCircles; + else if ((*anEntIt)->type() == ENTITY_ELLIPSE || (*anEntIt)->type() == ENTITY_ELLIPTIC_ARC) + ++aNbEllipses; + else if ((*anEntIt)->type() == ENTITY_BSPLINE) + ++aNbSplines; } - if (aNbCircles < 1) { + if (aNbCircles + aNbEllipses + aNbSplines < 1) { myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE(); return; } if (aNbLines == 1 && aNbCircles == 1) { myType = CONSTRAINT_TANGENT_CIRCLE_LINE; } - else if (aNbCircles == 2) { - myType = CONSTRAINT_TANGENT_CIRCLE_CIRCLE; + else if (aNbLines + aNbCircles + aNbEllipses + aNbSplines == 2) { + myType = CONSTRAINT_TANGENT_CURVE_CURVE; isArcArcInternal = isArcArcTangencyInternal(myAttributes.front(), myAttributes.back()); } else { @@ -105,36 +161,113 @@ void SketchSolver_ConstraintTangent::rebuild() return; } - FeaturePtr aFeature1, aFeature2; - getTangentFeatures(myBaseConstraint, aFeature1, aFeature2); + FeaturePtr aFeatures[2]; + getTangentFeatures(myBaseConstraint, aFeatures[0], aFeatures[1]); // check number of coincident points - std::list aCoincidentPoints = coincidentPoints(aFeature1, aFeature2); - if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE && aCoincidentPoints.size() > 1) { + std::set aCoincidentPoints = coincidentBoundaryPoints(aFeatures[0], aFeatures[1]); + if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE && aCoincidentPoints.size() > 2) { myErrorMsg = SketchSolver_Error::TANGENCY_FAILED(); return; } + EntityWrapperPtr aTgEntities[2] = { myAttributes.front(), myAttributes.back() }; + + if (aCoincidentPoints.empty()) { + // Try to find non-boundary points coincident with both features. + // It is necesasry to create tangency with ellipse. + if (aNbEllipses > 0) + aCoincidentPoints = coincidentPoints(aFeatures[0], aFeatures[1]); + } + else if (aNbSplines > 0) { + // General approach applying tangency to B-spline leads to hang-up in PlaneGCS. + // So, the tangency will be applied for the construction segment instead of B-spline curve. + for (int i = 0; i < 2; ++i) { + if (aTgEntities[i]->type() == ENTITY_BSPLINE) { + EdgeWrapperPtr anEdge = + std::dynamic_pointer_cast(aTgEntities[i]); + std::shared_ptr aBSpline = + std::dynamic_pointer_cast(anEdge->entity()); + + // which boundary is coincident? + GCS::Point aPoint1, aPoint2; + for (std::set::iterator aPIt = aCoincidentPoints.begin(); + aPIt != aCoincidentPoints.end(); ++aPIt) { + if ((*aPIt)->owner() == aFeatures[i]) { + if ((*aPIt)->id() == SketchPlugin_BSpline::START_ID()) { + aPoint1 = aBSpline->poles[0]; + aPoint2 = aBSpline->poles[1]; + } + else if ((*aPIt)->id() == SketchPlugin_BSpline::END_ID()) { + aPoint1 = aBSpline->poles[aBSpline->poles.size() - 2]; + aPoint2 = aBSpline->poles[aBSpline->poles.size() - 1]; + } + break; + } + } + + // substitute B-spline by its boundary segment + std::shared_ptr aSegment(new GCS::Line); + aSegment->p1 = aPoint1; + aSegment->p2 = aPoint2; + aTgEntities[i] = EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aSegment)); + --aNbSplines; + ++aNbLines; + } + } + } + EntityWrapperPtr aSharedPointEntity; + std::list anAuxConstraints; if (!aCoincidentPoints.empty()) { - mySharedPoint = aCoincidentPoints.front(); + mySharedPoint = *aCoincidentPoints.begin(); aSharedPointEntity = myStorage->entity(mySharedPoint); } + else if (aNbEllipses + aNbSplines > 0) { + // create auxiliary point + GCSPointPtr aPoint(new GCS::Point); + aPoint->x = aStorage->createParameter(); + aPoint->y = aStorage->createParameter(); + calculateTangencyPoint(aTgEntities[0], aTgEntities[1], aPoint); + + myAuxPoint.reset(new PlaneGCSSolver_PointWrapper(aPoint)); + aSharedPointEntity = myAuxPoint; + + EntityWrapperPtr aDummy; + for (int i = 0; i < 2; ++i) { + // create auxiliary parameters for coincidence with B-spline + if (aTgEntities[i]->type() == ENTITY_BSPLINE) + myAuxParameters[i].reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter())); + + // create auxiliary coincident constraints for tangency with ellipse + ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(), + CONSTRAINT_PT_ON_CURVE, myAuxParameters[i], + aSharedPointEntity, aDummy, aTgEntities[i], aDummy); + anAuxConstraints.insert(anAuxConstraints.end(), + aCoincidence->constraints().begin(), aCoincidence->constraints().end()); + } + } if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) { - mySolverConstraint = createArcLineTangency(myAttributes.front(), myAttributes.back(), + mySolverConstraint = createArcLineTangency(aTgEntities[0], aTgEntities[1], aSharedPointEntity, &myCurveCurveAngle); } else { - mySolverConstraint = createArcArcTangency(myAttributes.front(), myAttributes.back(), + mySolverConstraint = createCurveCurveTangency(aTgEntities[0], aTgEntities[1], isArcArcInternal, aSharedPointEntity, &myCurveCurveAngle); } + if (!anAuxConstraints.empty()) { + anAuxConstraints.insert(anAuxConstraints.end(), mySolverConstraint->constraints().begin(), + mySolverConstraint->constraints().end()); + mySolverConstraint->setConstraints(anAuxConstraints); + } + myStorage->addConstraint(myBaseConstraint, mySolverConstraint); } void SketchSolver_ConstraintTangent::adjustConstraint() { - if (myType == CONSTRAINT_TANGENT_CIRCLE_CIRCLE) { + if (myType == CONSTRAINT_TANGENT_CURVE_CURVE) { EntityWrapperPtr anEntity1 = myStorage->entity(myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A())); EntityWrapperPtr anEntity2 = @@ -183,21 +316,48 @@ void SketchSolver_ConstraintTangent::notify(const FeaturePtr& theFeature, if (aNbCoincidentFeatures == 2) isRebuild = true; } - } else if (mySharedPoint) { - // The features are tangent in the shared point, but the coincidence has been removed. - // Check if the coincidence is the same. - std::list aCoincidentPoints = coincidentPoints(aTgFeat1, aTgFeat2); - isRebuild = true; - std::list::iterator anIt = aCoincidentPoints.begin(); - for (; anIt != aCoincidentPoints.end() && isRebuild; ++anIt) - if (*anIt == mySharedPoint) - isRebuild = false; // the coincidence is still exists => nothing to change + } + + if (!isRebuild) { + if (mySharedPoint) { + // The features are tangent in the shared point, but the coincidence has been removed/updated. + // Check if the coincidence is the same. + std::set aCoincidentPoints = coincidentBoundaryPoints(aTgFeat1, aTgFeat2); + isRebuild = true; + std::set::iterator anIt = aCoincidentPoints.begin(); + for (; anIt != aCoincidentPoints.end() && isRebuild; ++anIt) + if (*anIt == mySharedPoint) + isRebuild = false; // the coincidence is still exists => nothing to change + } + else { + // check both features have a coincident point + std::set aCoincidentPoints = coincidentPoints(aTgFeat1, aTgFeat2); + isRebuild = (bool)(myAuxPoint.get()) == (!aCoincidentPoints.empty()); + } } if (isRebuild) rebuild(); } +bool SketchSolver_ConstraintTangent::remove() +{ + if (myAuxPoint) { + std::shared_ptr aStorage = + std::dynamic_pointer_cast(myStorage); + + GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint); + if (myAuxParameters[0]) + aParams.insert(myAuxParameters[0]->scalar()); + if (myAuxParameters[1]) + aParams.insert(myAuxParameters[1]->scalar()); + aStorage->removeParameters(aParams); + myAuxPoint = EntityWrapperPtr(); + myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr(); + } + return SketchSolver_Constraint::remove(); +} + @@ -218,13 +378,22 @@ std::set collectCoincidences(FeaturePtr theFeature1, FeaturePtr theF const std::set& aRefs2 = theFeature2->data()->refsToMe(); std::set aCoincidences; + std::map aCoincidentPoints; std::set::const_iterator anIt; // collect coincidences referred to the first feature for (anIt = aRefs1.begin(); anIt != aRefs1.end(); ++anIt) { FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner()); - if (aRef && aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID()) + if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() || + aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) { aCoincidences.insert(aRef); + AttributeRefAttrPtr aRefAttrA = aRef->refattr(SketchPlugin_Constraint::ENTITY_A()); + if (!aRefAttrA->isObject()) + aCoincidentPoints[aRefAttrA->attr()] = aRef; + AttributeRefAttrPtr aRefAttrB = aRef->refattr(SketchPlugin_Constraint::ENTITY_B()); + if (!aRefAttrB->isObject()) + aCoincidentPoints[aRefAttrB->attr()] = aRef; + } } // leave only coincidences referred to the second feature @@ -233,27 +402,123 @@ std::set collectCoincidences(FeaturePtr theFeature1, FeaturePtr theF FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner()); if (aCoincidences.find(aRef) != aCoincidences.end()) aCoincidencesBetweenFeatures.insert(aRef); + else if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() || + aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) { + for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) { + AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i)); + if (aRefAttr && !aRefAttr->isObject()) { + std::map::iterator aFound = + aCoincidentPoints.find(aRefAttr->attr()); + if (aFound != aCoincidentPoints.end()) { + aCoincidencesBetweenFeatures.insert(aRef); + aCoincidencesBetweenFeatures.insert(aFound->second); + } + } + } + } } return aCoincidencesBetweenFeatures; } -std::list coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2) +std::set coincidentBoundaryPoints(FeaturePtr theFeature1, FeaturePtr theFeature2) { std::set aCoincidences = collectCoincidences(theFeature1, theFeature2); // collect points only - std::list aCoincidentPoints; + std::map > aCoincidentPoints; std::set::const_iterator aCIt = aCoincidences.begin(); for (; aCIt != aCoincidences.end(); ++ aCIt) { for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) { - AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_A()); - if (aRefAttr && !aRefAttr->isObject()) { - aCoincidentPoints.push_back(aRefAttr->attr()); - break; + AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i)); + if (!aRefAttr || aRefAttr->isObject()) + continue; + + AttributePtr anAttr = aRefAttr->attr(); + FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner()); + if (anOwner == theFeature1 || anOwner == theFeature2) { + if (anAttr->id() == SketchPlugin_BSplineBase::POLES_ID()) { + AttributePoint2DArrayPtr aPoles = + std::dynamic_pointer_cast(anAttr); + + AttributeIntegerPtr anIndex; + if (anOwner->getKind() == SketchPlugin_BSpline::ID()) { + anIndex = (*aCIt)->integer(i == 0 ? + SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A() : + SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B()); + } + if (anIndex) { + if (anIndex->value() == 0) + anAttr = anOwner->attribute(SketchPlugin_BSpline::START_ID()); + else if (anIndex->value() + 1 == aPoles->size()) + anAttr = anOwner->attribute(SketchPlugin_BSpline::END_ID()); + if (anAttr) + aCoincidentPoints[anOwner].insert(anAttr); + } + } + else if (anAttr->id() != SketchPlugin_Arc::CENTER_ID() && + anAttr->id() != SketchPlugin_Circle::CENTER_ID()) + aCoincidentPoints[anOwner].insert(anAttr); } } } - return aCoincidentPoints; + + std::set aBoundaryPoints; + if (aCoincidentPoints.size() == 2) { + for (std::map >::iterator anIt = aCoincidentPoints.begin(); + anIt != aCoincidentPoints.end(); ++anIt) + aBoundaryPoints.insert(anIt->second.begin(), anIt->second.end()); + } + return aBoundaryPoints; +} + +static std::set refsToFeatureAndResults(FeaturePtr theFeature) +{ + std::set aRefs = theFeature->data()->refsToMe(); + const std::list& aResults = theFeature->results(); + for (std::list::const_iterator anIt = aResults.begin(); + anIt != aResults.end(); ++anIt) { + const std::set& aResRefs = (*anIt)->data()->refsToMe(); + aRefs.insert(aResRefs.begin(), aResRefs.end()); + } + return aRefs; +} + +// collect all points coincident with the feature +static std::set pointsOnFeature(FeaturePtr theFeature) +{ + std::set aPoints; + + std::set aRefs = refsToFeatureAndResults(theFeature); + for (std::set::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) { + FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner()); + if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() || + aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID() || + aRef->getKind() == SketchPlugin_ConstraintMiddle::ID())) { + for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) { + AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i)); + if (aRefAttr) { + AttributePtr anAttr = aRefAttr->attr(); + if (anAttr && anAttr->id() != SketchPlugin_Arc::CENTER_ID() && + anAttr->id() != SketchPlugin_Circle::CENTER_ID()) + aPoints.insert(anAttr); + } + } + } + } + return aPoints; +} + +std::set coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2) +{ + std::set aPointsOnF1 = pointsOnFeature(theFeature1); + std::set aPointsOnF2 = pointsOnFeature(theFeature2); + + std::set aCommonPoints; + for (std::set::iterator anIt = aPointsOnF1.begin(); + anIt != aPointsOnF1.end(); ++anIt) + if (aPointsOnF2.find(*anIt) != aPointsOnF2.end()) + aCommonPoints.insert(*anIt); + return aCommonPoints; } bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, EntityWrapperPtr theArc2) @@ -307,12 +572,13 @@ ConstraintWrapperPtr createArcLineTangency(EntityWrapperPtr theEntity1, std::shared_ptr aCirc = std::dynamic_pointer_cast(anEntCirc->entity()); + std::shared_ptr anArc = std::dynamic_pointer_cast(aCirc); + std::shared_ptr aLine = std::dynamic_pointer_cast(anEntLine->entity()); GCSConstraintPtr aNewConstr; - if (theSharedPoint) { - std::shared_ptr anArc = std::dynamic_pointer_cast(aCirc); + if (theSharedPoint && anArc) { // do not process shared point between circle and line GCSPointPtr aPoint = std::dynamic_pointer_cast(theSharedPoint)->point(); @@ -328,32 +594,65 @@ ConstraintWrapperPtr createArcLineTangency(EntityWrapperPtr theEntity1, new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CIRCLE_LINE)); } -ConstraintWrapperPtr createArcArcTangency(EntityWrapperPtr theEntity1, - EntityWrapperPtr theEntity2, - bool theInternalTangency, - EntityWrapperPtr theSharedPoint, - double* theAngle) +ConstraintWrapperPtr createCurveCurveTangency(EntityWrapperPtr theEntity1, + EntityWrapperPtr theEntity2, + bool theInternalTangency, + EntityWrapperPtr theSharedPoint, + double* theAngle) { - std::shared_ptr aCirc1 = - std::dynamic_pointer_cast(GCS_EDGE_WRAPPER(theEntity1)->entity()); - std::shared_ptr aCirc2 = - std::dynamic_pointer_cast(GCS_EDGE_WRAPPER(theEntity2)->entity()); + GCSCurvePtr aCurve1 = + std::dynamic_pointer_cast(GCS_EDGE_WRAPPER(theEntity1)->entity()); + GCSCurvePtr aCurve2 = + std::dynamic_pointer_cast(GCS_EDGE_WRAPPER(theEntity2)->entity()); GCSConstraintPtr aNewConstr; if (theSharedPoint) { - std::shared_ptr anArc1 = std::dynamic_pointer_cast(aCirc1); - std::shared_ptr anArc2 = std::dynamic_pointer_cast(aCirc2); GCSPointPtr aPoint = std::dynamic_pointer_cast(theSharedPoint)->point(); - adjustAngleBetweenCurves(anArc1, anArc2, aPoint, theAngle); + adjustAngleBetweenCurves(aCurve1, aCurve2, aPoint, theAngle); aNewConstr = - GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*anArc1, *anArc2, *aPoint, theAngle)); + GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*aCurve1, *aCurve2, *aPoint, theAngle)); } else { + std::shared_ptr aCirc1 = std::dynamic_pointer_cast(aCurve1); + std::shared_ptr aCirc2 = std::dynamic_pointer_cast(aCurve2); aNewConstr = GCSConstraintPtr(new GCS::ConstraintTangentCircumf(aCirc1->center, aCirc2->center, aCirc1->rad, aCirc2->rad, theInternalTangency)); } return ConstraintWrapperPtr( - new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CIRCLE_CIRCLE)); + new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CURVE_CURVE)); +} + +void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2, + GCSPointPtr& theTangencyPoint) +{ + std::shared_ptr anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve1); + EntityWrapperPtr aCurve2 = theCurve2; + if (!anEllipse) { + // try converting to ellipse the second curve + anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve2); + if (!anEllipse) + return; // no one curve is ellipse + aCurve2 = theCurve1; + } + + GeomPnt2dPtr aP1, aP2; + if (aCurve2->type() == ENTITY_LINE) { + std::shared_ptr aLine = PlaneGCSSolver_Tools::line(aCurve2); + anEllipse->distance(aLine, aP1, aP2); + } + else if (aCurve2->type() == ENTITY_ARC || aCurve2->type() == ENTITY_CIRCLE) { + std::shared_ptr aCircle = PlaneGCSSolver_Tools::circle(aCurve2); + anEllipse->distance(aCircle, aP1, aP2); + } + else if (aCurve2->type() == ENTITY_ELLIPSE || aCurve2->type() == ENTITY_ELLIPTIC_ARC) { + std::shared_ptr anEl2 = PlaneGCSSolver_Tools::ellipse(aCurve2); + anEllipse->distance(anEl2, aP1, aP2); + } + + if (aP1 && aP2) { + *theTangencyPoint->x = 0.5 * (aP1->x() + aP2->x()); + *theTangencyPoint->y = 0.5 * (aP1->y() + aP2->y()); + } }