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 <ModelAPI_AttributeInteger.h>
36 #include <SketchPlugin_Arc.h>
37 #include <SketchPlugin_BSpline.h>
38 #include <SketchPlugin_Circle.h>
39 #include <SketchPlugin_ConstraintCoincidence.h>
40 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
41 #include <SketchPlugin_ConstraintMiddle.h>
45 #define GCS_EDGE_WRAPPER(x) std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(x)
47 /// \brief Obtain tangent features from the constraint
48 static void getTangentFeatures(const ConstraintPtr& theConstraint,
49 FeaturePtr& theFeature1,
50 FeaturePtr& theFeature2);
52 /// \brief Obtain all coincident constraints between features
53 static std::set<FeaturePtr> collectCoincidences(FeaturePtr theFeature1, FeaturePtr theFeature2);
55 /// \brief Check whether the entities has only one shared point or less.
56 /// Return list of coincident points.
57 static std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1,
58 FeaturePtr theFeature2);
60 /// \brief Collect points coincident with each of two features
61 static std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2);
63 /// \brief Check if two connected arcs have centers
64 /// in same direction relatively to connection point
65 static bool isArcArcTangencyInternal(EntityWrapperPtr theArc1,
66 EntityWrapperPtr theArc2);
68 static ConstraintWrapperPtr
69 createArcLineTangency(EntityWrapperPtr theEntity1,
70 EntityWrapperPtr theEntity2,
71 EntityWrapperPtr theShapedPoint = EntityWrapperPtr(),
72 double* theAngle = 0);
74 static ConstraintWrapperPtr
75 createCurveCurveTangency(EntityWrapperPtr theEntity1,
76 EntityWrapperPtr theEntity2,
77 bool theInternalTangency,
78 EntityWrapperPtr theSharedPoint = EntityWrapperPtr(),
79 double* theAngle = 0);
81 static void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
82 GCSPointPtr& theTangencyPoint);
85 void SketchSolver_ConstraintTangent::process()
88 if (!myBaseConstraint || !myStorage) {
89 // Not enough parameters are assigned
93 EntityWrapperPtr aValue;
94 std::vector<EntityWrapperPtr> anAttributes;
95 SketchSolver_Constraint::getAttributes(aValue, anAttributes);
96 if (!myErrorMsg.empty())
100 if (!myErrorMsg.empty())
103 myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
106 void SketchSolver_ConstraintTangent::rebuild()
108 if (mySolverConstraint)
109 myStorage->removeConstraint(myBaseConstraint);
111 std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
112 std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
114 mySolverConstraint = ConstraintWrapperPtr();
115 mySharedPoint = AttributePtr();
117 GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
118 if (myAuxParameters[0])
119 aParams.insert(myAuxParameters[0]->scalar());
120 if (myAuxParameters[1])
121 aParams.insert(myAuxParameters[1]->scalar());
122 aStorage->removeParameters(aParams);
123 myAuxPoint = EntityWrapperPtr();
124 myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
127 // Check the quantity of entities of each type and their order (arcs first)
132 std::list<EntityWrapperPtr>::iterator anEntIt = myAttributes.begin();
133 for (; anEntIt != myAttributes.end(); ++anEntIt) {
134 if (!(*anEntIt).get())
136 if ((*anEntIt)->type() == ENTITY_LINE)
138 else if ((*anEntIt)->type() == ENTITY_ARC || (*anEntIt)->type() == ENTITY_CIRCLE)
140 else if ((*anEntIt)->type() == ENTITY_ELLIPSE || (*anEntIt)->type() == ENTITY_ELLIPTIC_ARC)
142 else if ((*anEntIt)->type() == ENTITY_BSPLINE)
146 if (aNbCircles + aNbEllipses + aNbSplines < 1) {
147 myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
150 if (aNbLines == 1 && aNbCircles == 1) {
151 myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
153 else if (aNbLines + aNbCircles + aNbEllipses + aNbSplines == 2) {
154 myType = CONSTRAINT_TANGENT_CURVE_CURVE;
155 isArcArcInternal = isArcArcTangencyInternal(myAttributes.front(), myAttributes.back());
158 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
162 FeaturePtr aFeatures[2];
163 getTangentFeatures(myBaseConstraint, aFeatures[0], aFeatures[1]);
165 // check number of coincident points
166 std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aFeatures[0], aFeatures[1]);
167 if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE && aCoincidentPoints.size() > 2) {
168 myErrorMsg = SketchSolver_Error::TANGENCY_FAILED();
172 EntityWrapperPtr aTgEntities[2] = { myAttributes.front(), myAttributes.back() };
174 if (aCoincidentPoints.empty()) {
175 // Try to find non-boundary points coincident with both features.
176 // It is necesasry to create tangency with ellipse.
178 aCoincidentPoints = coincidentPoints(aFeatures[0], aFeatures[1]);
180 else if (aNbSplines > 0) {
181 // General approach applying tangency to B-spline leads to hang-up in PlaneGCS.
182 // So, the tangency will be applied for the construction segment instead of B-spline curve.
183 for (int i = 0; i < 2; ++i) {
184 if (aTgEntities[i]->type() == ENTITY_BSPLINE) {
185 EdgeWrapperPtr anEdge =
186 std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aTgEntities[i]);
187 std::shared_ptr<GCS::BSpline> aBSpline =
188 std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
190 // which boundary is coincident?
191 GCS::Point aPoint1, aPoint2;
192 for (std::set<AttributePtr>::iterator aPIt = aCoincidentPoints.begin();
193 aPIt != aCoincidentPoints.end(); ++aPIt) {
194 if ((*aPIt)->owner() == aFeatures[i]) {
195 if ((*aPIt)->id() == SketchPlugin_BSpline::START_ID()) {
196 aPoint1 = aBSpline->poles[0];
197 aPoint2 = aBSpline->poles[1];
199 else if ((*aPIt)->id() == SketchPlugin_BSpline::END_ID()) {
200 aPoint1 = aBSpline->poles[aBSpline->poles.size() - 2];
201 aPoint2 = aBSpline->poles[aBSpline->poles.size() - 1];
207 // substitute B-spline by its boundary segment
208 std::shared_ptr<GCS::Line> aSegment(new GCS::Line);
209 aSegment->p1 = aPoint1;
210 aSegment->p2 = aPoint2;
211 aTgEntities[i] = EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aSegment));
218 EntityWrapperPtr aSharedPointEntity;
219 std::list<GCSConstraintPtr> anAuxConstraints;
220 if (!aCoincidentPoints.empty()) {
221 mySharedPoint = *aCoincidentPoints.begin();
222 aSharedPointEntity = myStorage->entity(mySharedPoint);
224 else if (aNbEllipses + aNbSplines > 0) {
225 // create auxiliary point
226 GCSPointPtr aPoint(new GCS::Point);
227 aPoint->x = aStorage->createParameter();
228 aPoint->y = aStorage->createParameter();
229 calculateTangencyPoint(aTgEntities[0], aTgEntities[1], aPoint);
231 myAuxPoint.reset(new PlaneGCSSolver_PointWrapper(aPoint));
232 aSharedPointEntity = myAuxPoint;
234 EntityWrapperPtr aDummy;
235 for (int i = 0; i < 2; ++i) {
236 // create auxiliary parameters for coincidence with B-spline
237 if (aTgEntities[i]->type() == ENTITY_BSPLINE)
238 myAuxParameters[i].reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
240 // create auxiliary coincident constraints for tangency with ellipse
241 ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
242 CONSTRAINT_PT_ON_CURVE, myAuxParameters[i],
243 aSharedPointEntity, aDummy, aTgEntities[i], aDummy);
244 anAuxConstraints.insert(anAuxConstraints.end(),
245 aCoincidence->constraints().begin(), aCoincidence->constraints().end());
249 if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
250 mySolverConstraint = createArcLineTangency(aTgEntities[0], aTgEntities[1],
251 aSharedPointEntity, &myCurveCurveAngle);
253 mySolverConstraint = createCurveCurveTangency(aTgEntities[0], aTgEntities[1],
254 isArcArcInternal, aSharedPointEntity, &myCurveCurveAngle);
257 if (!anAuxConstraints.empty()) {
258 anAuxConstraints.insert(anAuxConstraints.end(), mySolverConstraint->constraints().begin(),
259 mySolverConstraint->constraints().end());
260 mySolverConstraint->setConstraints(anAuxConstraints);
263 myStorage->addConstraint(myBaseConstraint, mySolverConstraint);
266 void SketchSolver_ConstraintTangent::adjustConstraint()
268 if (myType == CONSTRAINT_TANGENT_CURVE_CURVE) {
269 EntityWrapperPtr anEntity1 =
270 myStorage->entity(myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
271 EntityWrapperPtr anEntity2 =
272 myStorage->entity(myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
274 if (isArcArcInternal != isArcArcTangencyInternal(anEntity1, anEntity2))
279 void SketchSolver_ConstraintTangent::notify(const FeaturePtr& theFeature,
280 PlaneGCSSolver_Update* theUpdater)
282 if (theFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
285 // base constraint may become invalid (for example, during undo)
286 if (!myBaseConstraint->data() || !myBaseConstraint->data()->isValid())
289 FeaturePtr aTgFeat1, aTgFeat2;
290 getTangentFeatures(myBaseConstraint, aTgFeat1, aTgFeat2);
292 bool isRebuild = false;
293 if (theFeature->data() && theFeature->data()->isValid()) {
294 // the constraint has been created
295 if (!mySharedPoint) {
296 // features has no shared point, check whether coincidence constraint binds these features)
297 int aNbCoincidentFeatures = 0;
298 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
299 AttributeRefAttrPtr aRefAttr = theFeature->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
304 if (aRefAttr->isObject())
305 anObj = aRefAttr->object();
307 anObj = aRefAttr->attr()->owner();
309 FeaturePtr aFeature = ModelAPI_Feature::feature(anObj);
310 if (aFeature == aTgFeat1 || aFeature == aTgFeat2)
311 ++aNbCoincidentFeatures;
314 if (aNbCoincidentFeatures == 2)
321 // The features are tangent in the shared point, but the coincidence has been removed/updated.
322 // Check if the coincidence is the same.
323 std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aTgFeat1, aTgFeat2);
325 std::set<AttributePtr>::iterator anIt = aCoincidentPoints.begin();
326 for (; anIt != aCoincidentPoints.end() && isRebuild; ++anIt)
327 if (*anIt == mySharedPoint)
328 isRebuild = false; // the coincidence is still exists => nothing to change
331 // check both features have a coincident point
332 std::set<AttributePtr> aCoincidentPoints = coincidentPoints(aTgFeat1, aTgFeat2);
333 isRebuild = (bool)(myAuxPoint.get()) == (!aCoincidentPoints.empty());
341 bool SketchSolver_ConstraintTangent::remove()
344 std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
345 std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
347 GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
348 if (myAuxParameters[0])
349 aParams.insert(myAuxParameters[0]->scalar());
350 if (myAuxParameters[1])
351 aParams.insert(myAuxParameters[1]->scalar());
352 aStorage->removeParameters(aParams);
353 myAuxPoint = EntityWrapperPtr();
354 myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
356 return SketchSolver_Constraint::remove();
362 // ================== Auxiliary functions =================================
363 void getTangentFeatures(const ConstraintPtr& theConstraint,
364 FeaturePtr& theFeature1,
365 FeaturePtr& theFeature2)
367 AttributeRefAttrPtr aRefAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
368 theFeature1 = ModelAPI_Feature::feature(aRefAttr->object());
369 aRefAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
370 theFeature2 = ModelAPI_Feature::feature(aRefAttr->object());
373 std::set<FeaturePtr> collectCoincidences(FeaturePtr theFeature1, FeaturePtr theFeature2)
375 const std::set<AttributePtr>& aRefs1 = theFeature1->data()->refsToMe();
376 const std::set<AttributePtr>& aRefs2 = theFeature2->data()->refsToMe();
378 std::set<FeaturePtr> aCoincidences;
379 std::map<AttributePtr, FeaturePtr> aCoincidentPoints;
380 std::set<AttributePtr>::const_iterator anIt;
382 // collect coincidences referred to the first feature
383 for (anIt = aRefs1.begin(); anIt != aRefs1.end(); ++anIt) {
384 FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
385 if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
386 aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) {
387 aCoincidences.insert(aRef);
388 AttributeRefAttrPtr aRefAttrA = aRef->refattr(SketchPlugin_Constraint::ENTITY_A());
389 if (!aRefAttrA->isObject())
390 aCoincidentPoints[aRefAttrA->attr()] = aRef;
391 AttributeRefAttrPtr aRefAttrB = aRef->refattr(SketchPlugin_Constraint::ENTITY_B());
392 if (!aRefAttrB->isObject())
393 aCoincidentPoints[aRefAttrB->attr()] = aRef;
397 // leave only coincidences referred to the second feature
398 std::set<FeaturePtr> aCoincidencesBetweenFeatures;
399 for (anIt = aRefs2.begin(); anIt != aRefs2.end(); ++anIt) {
400 FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
401 if (aCoincidences.find(aRef) != aCoincidences.end())
402 aCoincidencesBetweenFeatures.insert(aRef);
403 else if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
404 aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) {
405 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
406 AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
407 if (aRefAttr && !aRefAttr->isObject()) {
408 std::map<AttributePtr, FeaturePtr>::iterator aFound =
409 aCoincidentPoints.find(aRefAttr->attr());
410 if (aFound != aCoincidentPoints.end()) {
411 aCoincidencesBetweenFeatures.insert(aRef);
412 aCoincidencesBetweenFeatures.insert(aFound->second);
419 return aCoincidencesBetweenFeatures;
422 std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
424 std::set<FeaturePtr> aCoincidences = collectCoincidences(theFeature1, theFeature2);
425 // collect points only
426 std::set<AttributePtr> aCoincidentPoints;
427 std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
428 for (; aCIt != aCoincidences.end(); ++ aCIt) {
429 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
430 AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
431 if (!aRefAttr || aRefAttr->isObject())
434 AttributePtr anAttr = aRefAttr->attr();
435 FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner());
436 if (anOwner == theFeature1 || anOwner == theFeature2) {
437 if (anAttr->id() == SketchPlugin_BSplineBase::POLES_ID()) {
438 AttributeIntegerPtr anIndex = (*aCIt)->integer(i == 0 ?
439 SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A() :
440 SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
442 if (anIndex->value() == 0)
443 anAttr = anOwner->attribute(SketchPlugin_BSpline::START_ID());
445 anAttr = anOwner->attribute(SketchPlugin_BSpline::END_ID());
447 aCoincidentPoints.insert(anAttr);
450 else if (anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
451 anAttr->id() != SketchPlugin_Circle::CENTER_ID())
452 aCoincidentPoints.insert(anAttr);
456 return aCoincidentPoints;
459 static std::set<AttributePtr> refsToFeatureAndResults(FeaturePtr theFeature)
461 std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
462 const std::list<ResultPtr>& aResults = theFeature->results();
463 for (std::list<ResultPtr>::const_iterator anIt = aResults.begin();
464 anIt != aResults.end(); ++anIt) {
465 const std::set<AttributePtr>& aResRefs = (*anIt)->data()->refsToMe();
466 aRefs.insert(aResRefs.begin(), aResRefs.end());
471 // collect all points coincident with the feature
472 static std::set<AttributePtr> pointsOnFeature(FeaturePtr theFeature)
474 std::set<AttributePtr> aPoints;
476 std::set<AttributePtr> aRefs = refsToFeatureAndResults(theFeature);
477 for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
478 FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
479 if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
480 aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID() ||
481 aRef->getKind() == SketchPlugin_ConstraintMiddle::ID())) {
482 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
483 AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
485 AttributePtr anAttr = aRefAttr->attr();
486 if (anAttr && anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
487 anAttr->id() != SketchPlugin_Circle::CENTER_ID())
488 aPoints.insert(anAttr);
496 std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
498 std::set<AttributePtr> aPointsOnF1 = pointsOnFeature(theFeature1);
499 std::set<AttributePtr> aPointsOnF2 = pointsOnFeature(theFeature2);
501 std::set<AttributePtr> aCommonPoints;
502 for (std::set<AttributePtr>::iterator anIt = aPointsOnF1.begin();
503 anIt != aPointsOnF1.end(); ++anIt)
504 if (aPointsOnF2.find(*anIt) != aPointsOnF2.end())
505 aCommonPoints.insert(*anIt);
506 return aCommonPoints;
509 bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, EntityWrapperPtr theArc2)
511 std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(
512 GCS_EDGE_WRAPPER(theArc1)->entity());
513 std::shared_ptr<GCS::Circle> aCirc2 = std::dynamic_pointer_cast<GCS::Circle>(
514 GCS_EDGE_WRAPPER(theArc2)->entity());
516 if (!aCirc1 || !aCirc2)
519 double aDX = *(aCirc1->center.x) - *(aCirc2->center.x);
520 double aDY = *(aCirc1->center.y) - *(aCirc2->center.y);
521 double aDist = sqrt(aDX * aDX + aDY * aDY);
523 return (aDist < *(aCirc1->rad) || aDist < *(aCirc2->rad));
526 // sets angle to 0 or 180 degrees
527 static void adjustAngleBetweenCurves(const GCSCurvePtr& theCurve1,
528 const GCSCurvePtr& theCurve2,
529 const GCSPointPtr& thePoint,
532 double anAngle = GCS::System().calculateAngleViaPoint(*theCurve1, *theCurve2, *thePoint);
533 // bring angle to [-pi..pi]
534 if (anAngle > PI) anAngle -= 2.0 * PI;
535 if (anAngle < -PI) anAngle += 2.0 * PI;
536 // set angle value according to the current angle between curves
537 if (fabs(anAngle) <= PI / 2.)
544 ConstraintWrapperPtr createArcLineTangency(EntityWrapperPtr theEntity1,
545 EntityWrapperPtr theEntity2,
546 EntityWrapperPtr theSharedPoint,
549 EdgeWrapperPtr anEntLine, anEntCirc;
550 if (theEntity1->type() == ENTITY_LINE) {
551 anEntLine = GCS_EDGE_WRAPPER(theEntity1);
552 anEntCirc = GCS_EDGE_WRAPPER(theEntity2);
554 anEntLine = GCS_EDGE_WRAPPER(theEntity2);
555 anEntCirc = GCS_EDGE_WRAPPER(theEntity1);
558 std::shared_ptr<GCS::Circle> aCirc =
559 std::dynamic_pointer_cast<GCS::Circle>(anEntCirc->entity());
560 std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(aCirc);
562 std::shared_ptr<GCS::Line> aLine =
563 std::dynamic_pointer_cast<GCS::Line>(anEntLine->entity());
565 GCSConstraintPtr aNewConstr;
566 if (theSharedPoint && anArc) { // do not process shared point between circle and line
568 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
570 adjustAngleBetweenCurves(anArc, aLine, aPoint, theAngle);
572 GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*anArc, *aLine, *aPoint, theAngle));
575 GCSConstraintPtr(new GCS::ConstraintP2LDistance(aCirc->center, *aLine, aCirc->rad));
578 return ConstraintWrapperPtr(
579 new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CIRCLE_LINE));
582 ConstraintWrapperPtr createCurveCurveTangency(EntityWrapperPtr theEntity1,
583 EntityWrapperPtr theEntity2,
584 bool theInternalTangency,
585 EntityWrapperPtr theSharedPoint,
588 GCSCurvePtr aCurve1 =
589 std::dynamic_pointer_cast<GCS::Curve>(GCS_EDGE_WRAPPER(theEntity1)->entity());
590 GCSCurvePtr aCurve2 =
591 std::dynamic_pointer_cast<GCS::Curve>(GCS_EDGE_WRAPPER(theEntity2)->entity());
593 GCSConstraintPtr aNewConstr;
594 if (theSharedPoint) {
596 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
598 adjustAngleBetweenCurves(aCurve1, aCurve2, aPoint, theAngle);
600 GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*aCurve1, *aCurve2, *aPoint, theAngle));
602 std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(aCurve1);
603 std::shared_ptr<GCS::Circle> aCirc2 = std::dynamic_pointer_cast<GCS::Circle>(aCurve2);
604 aNewConstr = GCSConstraintPtr(new GCS::ConstraintTangentCircumf(aCirc1->center, aCirc2->center,
605 aCirc1->rad, aCirc2->rad, theInternalTangency));
608 return ConstraintWrapperPtr(
609 new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CURVE_CURVE));
612 void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
613 GCSPointPtr& theTangencyPoint)
615 std::shared_ptr<GeomAPI_Ellipse2d> anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve1);
616 EntityWrapperPtr aCurve2 = theCurve2;
618 // try converting to ellipse the second curve
619 anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve2);
621 return; // no one curve is ellipse
625 GeomPnt2dPtr aP1, aP2;
626 if (aCurve2->type() == ENTITY_LINE) {
627 std::shared_ptr<GeomAPI_Lin2d> aLine = PlaneGCSSolver_Tools::line(aCurve2);
628 anEllipse->distance(aLine, aP1, aP2);
630 else if (aCurve2->type() == ENTITY_ARC || aCurve2->type() == ENTITY_CIRCLE) {
631 std::shared_ptr<GeomAPI_Circ2d> aCircle = PlaneGCSSolver_Tools::circle(aCurve2);
632 anEllipse->distance(aCircle, aP1, aP2);
634 else if (aCurve2->type() == ENTITY_ELLIPSE || aCurve2->type() == ENTITY_ELLIPTIC_ARC) {
635 std::shared_ptr<GeomAPI_Ellipse2d> anEl2 = PlaneGCSSolver_Tools::ellipse(aCurve2);
636 anEllipse->distance(anEl2, aP1, aP2);
640 *theTangencyPoint->x = 0.5 * (aP1->x() + aP2->x());
641 *theTangencyPoint->y = 0.5 * (aP1->y() + aP2->y());