1 // Copyright (C) 2014-2019 CEA/DEN, EDF R&D
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include <SketchSolver_ConstraintTangent.h>
21 #include <SketchSolver_Error.h>
23 #include <PlaneGCSSolver_EdgeWrapper.h>
24 #include <PlaneGCSSolver_PointWrapper.h>
25 #include <PlaneGCSSolver_Storage.h>
26 #include <PlaneGCSSolver_Tools.h>
27 #include <PlaneGCSSolver_UpdateCoincidence.h>
29 #include <GeomAPI_Circ2d.h>
30 #include <GeomAPI_Lin2d.h>
31 #include <GeomAPI_Pnt2d.h>
32 #include <GeomAPI_Ellipse2d.h>
34 #include <SketchPlugin_Arc.h>
35 #include <SketchPlugin_Circle.h>
36 #include <SketchPlugin_ConstraintCoincidence.h>
37 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
38 #include <SketchPlugin_ConstraintMiddle.h>
42 #define GCS_EDGE_WRAPPER(x) std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(x)
44 /// \brief Obtain tangent features from the constraint
45 static void getTangentFeatures(const ConstraintPtr& theConstraint,
46 FeaturePtr& theFeature1,
47 FeaturePtr& theFeature2);
49 /// \brief Obtain all coincident constraints between features
50 static std::set<FeaturePtr> collectCoincidences(FeaturePtr theFeature1, FeaturePtr theFeature2);
52 /// \brief Check whether the entities has only one shared point or less.
53 /// Return list of coincident points.
54 static std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1,
55 FeaturePtr theFeature2);
57 /// \brief Collect points coincident with each of two features
58 static std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2);
60 /// \brief Check if two connected arcs have centers
61 /// in same direction relatively to connection point
62 static bool isArcArcTangencyInternal(EntityWrapperPtr theArc1,
63 EntityWrapperPtr theArc2);
65 static ConstraintWrapperPtr
66 createArcLineTangency(EntityWrapperPtr theEntity1,
67 EntityWrapperPtr theEntity2,
68 EntityWrapperPtr theShapedPoint = EntityWrapperPtr(),
69 double* theAngle = 0);
71 static ConstraintWrapperPtr
72 createCurveCurveTangency(EntityWrapperPtr theEntity1,
73 EntityWrapperPtr theEntity2,
74 bool theInternalTangency,
75 EntityWrapperPtr theSharedPoint = EntityWrapperPtr(),
76 double* theAngle = 0);
78 static void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
79 GCSPointPtr& theTangencyPoint);
82 void SketchSolver_ConstraintTangent::process()
85 if (!myBaseConstraint || !myStorage) {
86 // Not enough parameters are assigned
90 EntityWrapperPtr aValue;
91 std::vector<EntityWrapperPtr> anAttributes;
92 SketchSolver_Constraint::getAttributes(aValue, anAttributes);
93 if (!myErrorMsg.empty())
97 if (!myErrorMsg.empty())
100 myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
103 void SketchSolver_ConstraintTangent::rebuild()
105 if (mySolverConstraint)
106 myStorage->removeConstraint(myBaseConstraint);
108 std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
109 std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
111 mySolverConstraint = ConstraintWrapperPtr();
112 mySharedPoint = AttributePtr();
114 GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
115 if (myAuxParameters[0])
116 aParams.insert(myAuxParameters[0]->scalar());
117 if (myAuxParameters[1])
118 aParams.insert(myAuxParameters[1]->scalar());
119 aStorage->removeParameters(aParams);
120 myAuxPoint = EntityWrapperPtr();
121 myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
124 // Check the quantity of entities of each type and their order (arcs first)
128 std::list<EntityWrapperPtr>::iterator anEntIt = myAttributes.begin();
129 for (; anEntIt != myAttributes.end(); ++anEntIt) {
130 if (!(*anEntIt).get())
132 if ((*anEntIt)->type() == ENTITY_LINE)
134 else if ((*anEntIt)->type() == ENTITY_ARC || (*anEntIt)->type() == ENTITY_CIRCLE)
136 else if ((*anEntIt)->type() == ENTITY_ELLIPSE || (*anEntIt)->type() == ENTITY_ELLIPTIC_ARC || (*anEntIt)->type() == ENTITY_BSPLINE)
140 if (aNbCircles + aNbEllipses < 1) {
141 myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
144 if (aNbLines == 1 && aNbCircles == 1) {
145 myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
147 else if (aNbLines + aNbCircles + aNbEllipses == 2) {
148 myType = CONSTRAINT_TANGENT_CURVE_CURVE;
149 isArcArcInternal = isArcArcTangencyInternal(myAttributes.front(), myAttributes.back());
152 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
156 FeaturePtr aFeature1, aFeature2;
157 getTangentFeatures(myBaseConstraint, aFeature1, aFeature2);
159 // check number of coincident points
160 std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aFeature1, aFeature2);
161 if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE && aCoincidentPoints.size() > 2) {
162 myErrorMsg = SketchSolver_Error::TANGENCY_FAILED();
166 // Try to find non-boundary points coincident with both features.
167 // It is necesasry to create tangency with ellipse
168 if (aCoincidentPoints.empty() && aNbEllipses > 0)
169 aCoincidentPoints = coincidentPoints(aFeature1, aFeature2);
171 EntityWrapperPtr aSharedPointEntity;
172 std::list<GCSConstraintPtr> anAuxConstraints;
173 if (!aCoincidentPoints.empty()) {
174 mySharedPoint = *aCoincidentPoints.begin();
175 aSharedPointEntity = myStorage->entity(mySharedPoint);
177 else if (aNbEllipses > 0) {
178 // create auxiliary point
179 GCSPointPtr aPoint(new GCS::Point);
180 aPoint->x = aStorage->createParameter();
181 aPoint->y = aStorage->createParameter();
182 calculateTangencyPoint(myAttributes.front(), myAttributes.back(), aPoint);
184 myAuxPoint.reset(new PlaneGCSSolver_PointWrapper(aPoint));
185 aSharedPointEntity = myAuxPoint;
187 // create auxiliary parameters for coincidence with B-spline
188 if (myAttributes.front()->type() == ENTITY_BSPLINE)
189 myAuxParameters[0].reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
190 if (myAttributes.back()->type() == ENTITY_BSPLINE)
191 myAuxParameters[1].reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
193 // create auxiliary coincident constraints for tangency with ellipse
194 EntityWrapperPtr aDummy;
195 ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
196 CONSTRAINT_PT_ON_CURVE, myAuxParameters[0],
197 aSharedPointEntity, aDummy, myAttributes.front(), aDummy);
198 anAuxConstraints = aCoincidence->constraints();
199 aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
200 CONSTRAINT_PT_ON_CURVE, myAuxParameters[1],
201 aSharedPointEntity, aDummy, myAttributes.back(), aDummy);
202 anAuxConstraints.insert(anAuxConstraints.end(),
203 aCoincidence->constraints().begin(), aCoincidence->constraints().end());
206 if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
207 mySolverConstraint = createArcLineTangency(myAttributes.front(), myAttributes.back(),
208 aSharedPointEntity, &myCurveCurveAngle);
210 mySolverConstraint = createCurveCurveTangency(myAttributes.front(), myAttributes.back(),
211 isArcArcInternal, aSharedPointEntity, &myCurveCurveAngle);
214 if (!anAuxConstraints.empty()) {
215 anAuxConstraints.insert(anAuxConstraints.end(), mySolverConstraint->constraints().begin(),
216 mySolverConstraint->constraints().end());
217 mySolverConstraint->setConstraints(anAuxConstraints);
220 myStorage->addConstraint(myBaseConstraint, mySolverConstraint);
223 void SketchSolver_ConstraintTangent::adjustConstraint()
225 if (myType == CONSTRAINT_TANGENT_CURVE_CURVE) {
226 EntityWrapperPtr anEntity1 =
227 myStorage->entity(myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
228 EntityWrapperPtr anEntity2 =
229 myStorage->entity(myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
231 if (isArcArcInternal != isArcArcTangencyInternal(anEntity1, anEntity2))
236 void SketchSolver_ConstraintTangent::notify(const FeaturePtr& theFeature,
237 PlaneGCSSolver_Update* theUpdater)
239 if (theFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
242 // base constraint may become invalid (for example, during undo)
243 if (!myBaseConstraint->data() || !myBaseConstraint->data()->isValid())
246 FeaturePtr aTgFeat1, aTgFeat2;
247 getTangentFeatures(myBaseConstraint, aTgFeat1, aTgFeat2);
249 bool isRebuild = false;
250 if (theFeature->data() && theFeature->data()->isValid()) {
251 // the constraint has been created
252 if (!mySharedPoint) {
253 // features has no shared point, check whether coincidence constraint binds these features)
254 int aNbCoincidentFeatures = 0;
255 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
256 AttributeRefAttrPtr aRefAttr = theFeature->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
261 if (aRefAttr->isObject())
262 anObj = aRefAttr->object();
264 anObj = aRefAttr->attr()->owner();
266 FeaturePtr aFeature = ModelAPI_Feature::feature(anObj);
267 if (aFeature == aTgFeat1 || aFeature == aTgFeat2)
268 ++aNbCoincidentFeatures;
271 if (aNbCoincidentFeatures == 2)
278 // The features are tangent in the shared point, but the coincidence has been removed/updated.
279 // Check if the coincidence is the same.
280 std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aTgFeat1, aTgFeat2);
282 std::set<AttributePtr>::iterator anIt = aCoincidentPoints.begin();
283 for (; anIt != aCoincidentPoints.end() && isRebuild; ++anIt)
284 if (*anIt == mySharedPoint)
285 isRebuild = false; // the coincidence is still exists => nothing to change
288 // check both features have a coincident point
289 std::set<AttributePtr> aCoincidentPoints = coincidentPoints(aTgFeat1, aTgFeat2);
290 isRebuild = (bool)(myAuxPoint.get()) == (!aCoincidentPoints.empty());
298 bool SketchSolver_ConstraintTangent::remove()
301 std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
302 std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
304 GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
305 if (myAuxParameters[0])
306 aParams.insert(myAuxParameters[0]->scalar());
307 if (myAuxParameters[1])
308 aParams.insert(myAuxParameters[1]->scalar());
309 aStorage->removeParameters(aParams);
310 myAuxPoint = EntityWrapperPtr();
311 myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
313 return SketchSolver_Constraint::remove();
319 // ================== Auxiliary functions =================================
320 void getTangentFeatures(const ConstraintPtr& theConstraint,
321 FeaturePtr& theFeature1,
322 FeaturePtr& theFeature2)
324 AttributeRefAttrPtr aRefAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
325 theFeature1 = ModelAPI_Feature::feature(aRefAttr->object());
326 aRefAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
327 theFeature2 = ModelAPI_Feature::feature(aRefAttr->object());
330 std::set<FeaturePtr> collectCoincidences(FeaturePtr theFeature1, FeaturePtr theFeature2)
332 const std::set<AttributePtr>& aRefs1 = theFeature1->data()->refsToMe();
333 const std::set<AttributePtr>& aRefs2 = theFeature2->data()->refsToMe();
335 std::set<FeaturePtr> aCoincidences;
336 std::set<AttributePtr>::const_iterator anIt;
338 // collect coincidences referred to the first feature
339 for (anIt = aRefs1.begin(); anIt != aRefs1.end(); ++anIt) {
340 FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
341 if (aRef && aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID())
342 aCoincidences.insert(aRef);
345 // leave only coincidences referred to the second feature
346 std::set<FeaturePtr> aCoincidencesBetweenFeatures;
347 for (anIt = aRefs2.begin(); anIt != aRefs2.end(); ++anIt) {
348 FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
349 if (aCoincidences.find(aRef) != aCoincidences.end())
350 aCoincidencesBetweenFeatures.insert(aRef);
353 return aCoincidencesBetweenFeatures;
356 std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
358 std::set<FeaturePtr> aCoincidences = collectCoincidences(theFeature1, theFeature2);
359 // collect points only
360 std::set<AttributePtr> aCoincidentPoints;
361 std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
362 for (; aCIt != aCoincidences.end(); ++ aCIt) {
363 AttributeRefAttrPtr aRefAttrA = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_A());
364 AttributeRefAttrPtr aRefAttrB = (*aCIt)->refattr(SketchPlugin_Constraint::ENTITY_B());
365 if (!aRefAttrA || aRefAttrA->isObject() ||
366 !aRefAttrB || aRefAttrB->isObject())
369 AttributePtr anAttrA = aRefAttrA->attr();
370 AttributePtr anAttrB = aRefAttrB->attr();
371 if (anAttrA->id() != SketchPlugin_Arc::CENTER_ID() &&
372 anAttrA->id() != SketchPlugin_Circle::CENTER_ID() &&
373 anAttrB->id() != SketchPlugin_Arc::CENTER_ID() &&
374 anAttrB->id() != SketchPlugin_Circle::CENTER_ID()) {
375 aCoincidentPoints.insert(anAttrA);
376 aCoincidentPoints.insert(anAttrB);
379 return aCoincidentPoints;
382 static std::set<AttributePtr> refsToFeatureAndResults(FeaturePtr theFeature)
384 std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
385 const std::list<ResultPtr>& aResults = theFeature->results();
386 for (std::list<ResultPtr>::const_iterator anIt = aResults.begin();
387 anIt != aResults.end(); ++anIt) {
388 const std::set<AttributePtr>& aResRefs = (*anIt)->data()->refsToMe();
389 aRefs.insert(aResRefs.begin(), aResRefs.end());
394 // collect all points coincident with the feature
395 static std::set<AttributePtr> pointsOnFeature(FeaturePtr theFeature)
397 std::set<AttributePtr> aPoints;
399 std::set<AttributePtr> aRefs = refsToFeatureAndResults(theFeature);
400 for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
401 FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
402 if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
403 aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID() ||
404 aRef->getKind() == SketchPlugin_ConstraintMiddle::ID())) {
405 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
406 AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
408 AttributePtr anAttr = aRefAttr->attr();
409 if (anAttr && anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
410 anAttr->id() != SketchPlugin_Circle::CENTER_ID())
411 aPoints.insert(anAttr);
419 std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
421 std::set<AttributePtr> aPointsOnF1 = pointsOnFeature(theFeature1);
422 std::set<AttributePtr> aPointsOnF2 = pointsOnFeature(theFeature2);
424 std::set<AttributePtr> aCommonPoints;
425 for (std::set<AttributePtr>::iterator anIt = aPointsOnF1.begin();
426 anIt != aPointsOnF1.end(); ++anIt)
427 if (aPointsOnF2.find(*anIt) != aPointsOnF2.end())
428 aCommonPoints.insert(*anIt);
429 return aCommonPoints;
432 bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, EntityWrapperPtr theArc2)
434 std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(
435 GCS_EDGE_WRAPPER(theArc1)->entity());
436 std::shared_ptr<GCS::Circle> aCirc2 = std::dynamic_pointer_cast<GCS::Circle>(
437 GCS_EDGE_WRAPPER(theArc2)->entity());
439 if (!aCirc1 || !aCirc2)
442 double aDX = *(aCirc1->center.x) - *(aCirc2->center.x);
443 double aDY = *(aCirc1->center.y) - *(aCirc2->center.y);
444 double aDist = sqrt(aDX * aDX + aDY * aDY);
446 return (aDist < *(aCirc1->rad) || aDist < *(aCirc2->rad));
449 // sets angle to 0 or 180 degrees
450 static void adjustAngleBetweenCurves(const GCSCurvePtr& theCurve1,
451 const GCSCurvePtr& theCurve2,
452 const GCSPointPtr& thePoint,
455 double anAngle = GCS::System().calculateAngleViaPoint(*theCurve1, *theCurve2, *thePoint);
456 // bring angle to [-pi..pi]
457 if (anAngle > PI) anAngle -= 2.0 * PI;
458 if (anAngle < -PI) anAngle += 2.0 * PI;
459 // set angle value according to the current angle between curves
460 if (fabs(anAngle) <= PI / 2.)
467 ConstraintWrapperPtr createArcLineTangency(EntityWrapperPtr theEntity1,
468 EntityWrapperPtr theEntity2,
469 EntityWrapperPtr theSharedPoint,
472 EdgeWrapperPtr anEntLine, anEntCirc;
473 if (theEntity1->type() == ENTITY_LINE) {
474 anEntLine = GCS_EDGE_WRAPPER(theEntity1);
475 anEntCirc = GCS_EDGE_WRAPPER(theEntity2);
477 anEntLine = GCS_EDGE_WRAPPER(theEntity2);
478 anEntCirc = GCS_EDGE_WRAPPER(theEntity1);
481 std::shared_ptr<GCS::Circle> aCirc =
482 std::dynamic_pointer_cast<GCS::Circle>(anEntCirc->entity());
483 std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(aCirc);
485 std::shared_ptr<GCS::Line> aLine =
486 std::dynamic_pointer_cast<GCS::Line>(anEntLine->entity());
488 GCSConstraintPtr aNewConstr;
489 if (theSharedPoint && anArc) { // do not process shared point between circle and line
491 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
493 adjustAngleBetweenCurves(anArc, aLine, aPoint, theAngle);
495 GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*anArc, *aLine, *aPoint, theAngle));
498 GCSConstraintPtr(new GCS::ConstraintP2LDistance(aCirc->center, *aLine, aCirc->rad));
501 return ConstraintWrapperPtr(
502 new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CIRCLE_LINE));
505 ConstraintWrapperPtr createCurveCurveTangency(EntityWrapperPtr theEntity1,
506 EntityWrapperPtr theEntity2,
507 bool theInternalTangency,
508 EntityWrapperPtr theSharedPoint,
511 GCSCurvePtr aCurve1 =
512 std::dynamic_pointer_cast<GCS::Curve>(GCS_EDGE_WRAPPER(theEntity1)->entity());
513 GCSCurvePtr aCurve2 =
514 std::dynamic_pointer_cast<GCS::Curve>(GCS_EDGE_WRAPPER(theEntity2)->entity());
516 GCSConstraintPtr aNewConstr;
517 if (theSharedPoint) {
519 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
521 adjustAngleBetweenCurves(aCurve1, aCurve2, aPoint, theAngle);
523 GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*aCurve1, *aCurve2, *aPoint, theAngle));
525 std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(aCurve1);
526 std::shared_ptr<GCS::Circle> aCirc2 = std::dynamic_pointer_cast<GCS::Circle>(aCurve2);
527 aNewConstr = GCSConstraintPtr(new GCS::ConstraintTangentCircumf(aCirc1->center, aCirc2->center,
528 aCirc1->rad, aCirc2->rad, theInternalTangency));
531 return ConstraintWrapperPtr(
532 new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CURVE_CURVE));
535 void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
536 GCSPointPtr& theTangencyPoint)
538 std::shared_ptr<GeomAPI_Ellipse2d> anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve1);
539 EntityWrapperPtr aCurve2 = theCurve2;
541 // try converting to ellipse the second curve
542 anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve2);
544 return; // no one curve is ellipse
548 GeomPnt2dPtr aP1, aP2;
549 if (aCurve2->type() == ENTITY_LINE) {
550 std::shared_ptr<GeomAPI_Lin2d> aLine = PlaneGCSSolver_Tools::line(aCurve2);
551 anEllipse->distance(aLine, aP1, aP2);
553 else if (aCurve2->type() == ENTITY_ARC || aCurve2->type() == ENTITY_CIRCLE) {
554 std::shared_ptr<GeomAPI_Circ2d> aCircle = PlaneGCSSolver_Tools::circle(aCurve2);
555 anEllipse->distance(aCircle, aP1, aP2);
557 else if (aCurve2->type() == ENTITY_ELLIPSE || aCurve2->type() == ENTITY_ELLIPTIC_ARC) {
558 std::shared_ptr<GeomAPI_Ellipse2d> anEl2 = PlaneGCSSolver_Tools::ellipse(aCurve2);
559 anEllipse->distance(anEl2, aP1, aP2);
563 *theTangencyPoint->x = 0.5 * (aP1->x() + aP2->x());
564 *theTangencyPoint->y = 0.5 * (aP1->y() + aP2->y());