1 // Copyright (C) 2014-2020 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 <GeomDataAPI_Point2DArray.h>
36 #include <ModelAPI_AttributeInteger.h>
38 #include <SketchPlugin_Arc.h>
39 #include <SketchPlugin_BSpline.h>
40 #include <SketchPlugin_Circle.h>
41 #include <SketchPlugin_ConstraintCoincidence.h>
42 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
43 #include <SketchPlugin_ConstraintMiddle.h>
47 #define GCS_EDGE_WRAPPER(x) std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(x)
49 /// \brief Obtain tangent features from the constraint
50 static void getTangentFeatures(const ConstraintPtr& theConstraint,
51 FeaturePtr& theFeature1,
52 FeaturePtr& theFeature2);
54 /// \brief Obtain all coincident constraints between features
55 static std::set<FeaturePtr> collectCoincidences(FeaturePtr theFeature1, FeaturePtr theFeature2);
57 /// \brief Check whether the entities has only one shared point or less.
58 /// Return list of coincident points.
59 static std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1,
60 FeaturePtr theFeature2);
62 /// \brief Collect points coincident with each of two features
63 static std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2);
65 /// \brief Check if two connected arcs have centers
66 /// in same direction relatively to connection point
67 static bool isArcArcTangencyInternal(EntityWrapperPtr theArc1,
68 EntityWrapperPtr theArc2);
70 static ConstraintWrapperPtr
71 createArcLineTangency(EntityWrapperPtr theEntity1,
72 EntityWrapperPtr theEntity2,
73 EntityWrapperPtr theShapedPoint = EntityWrapperPtr(),
74 double* theAngle = 0);
76 static ConstraintWrapperPtr
77 createCurveCurveTangency(EntityWrapperPtr theEntity1,
78 EntityWrapperPtr theEntity2,
79 bool theInternalTangency,
80 EntityWrapperPtr theSharedPoint = EntityWrapperPtr(),
81 double* theAngle = 0);
83 static void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
84 GCSPointPtr& theTangencyPoint);
87 void SketchSolver_ConstraintTangent::process()
90 if (!myBaseConstraint || !myStorage) {
91 // Not enough parameters are assigned
95 EntityWrapperPtr aValue;
96 std::vector<EntityWrapperPtr> anAttributes;
97 SketchSolver_Constraint::getAttributes(aValue, anAttributes);
98 if (!myErrorMsg.empty())
102 if (!myErrorMsg.empty())
105 myStorage->subscribeUpdates(this, PlaneGCSSolver_UpdateCoincidence::GROUP());
108 void SketchSolver_ConstraintTangent::rebuild()
110 if (mySolverConstraint)
111 myStorage->removeConstraint(myBaseConstraint);
113 std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
114 std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
116 mySolverConstraint = ConstraintWrapperPtr();
117 mySharedPoint = AttributePtr();
119 GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
120 if (myAuxParameters[0])
121 aParams.insert(myAuxParameters[0]->scalar());
122 if (myAuxParameters[1])
123 aParams.insert(myAuxParameters[1]->scalar());
124 aStorage->removeParameters(aParams);
125 myAuxPoint = EntityWrapperPtr();
126 myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
129 // Check the quantity of entities of each type and their order (arcs first)
134 std::list<EntityWrapperPtr>::iterator anEntIt = myAttributes.begin();
135 for (; anEntIt != myAttributes.end(); ++anEntIt) {
136 if (!(*anEntIt).get())
138 if ((*anEntIt)->type() == ENTITY_LINE)
140 else if ((*anEntIt)->type() == ENTITY_ARC || (*anEntIt)->type() == ENTITY_CIRCLE)
142 else if ((*anEntIt)->type() == ENTITY_ELLIPSE || (*anEntIt)->type() == ENTITY_ELLIPTIC_ARC)
144 else if ((*anEntIt)->type() == ENTITY_BSPLINE)
148 if (aNbCircles + aNbEllipses + aNbSplines < 1) {
149 myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
152 if (aNbLines == 1 && aNbCircles == 1) {
153 myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
155 else if (aNbLines + aNbCircles + aNbEllipses + aNbSplines == 2) {
156 myType = CONSTRAINT_TANGENT_CURVE_CURVE;
157 isArcArcInternal = isArcArcTangencyInternal(myAttributes.front(), myAttributes.back());
160 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
164 FeaturePtr aFeatures[2];
165 getTangentFeatures(myBaseConstraint, aFeatures[0], aFeatures[1]);
167 // check number of coincident points
168 std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aFeatures[0], aFeatures[1]);
169 if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE && aCoincidentPoints.size() > 2) {
170 myErrorMsg = SketchSolver_Error::TANGENCY_FAILED();
174 EntityWrapperPtr aTgEntities[2] = { myAttributes.front(), myAttributes.back() };
176 if (aCoincidentPoints.empty()) {
177 // Try to find non-boundary points coincident with both features.
178 // It is necesasry to create tangency with ellipse.
180 aCoincidentPoints = coincidentPoints(aFeatures[0], aFeatures[1]);
182 else if (aNbSplines > 0) {
183 // General approach applying tangency to B-spline leads to hang-up in PlaneGCS.
184 // So, the tangency will be applied for the construction segment instead of B-spline curve.
185 for (int i = 0; i < 2; ++i) {
186 if (aTgEntities[i]->type() == ENTITY_BSPLINE) {
187 EdgeWrapperPtr anEdge =
188 std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aTgEntities[i]);
189 std::shared_ptr<GCS::BSpline> aBSpline =
190 std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
192 // which boundary is coincident?
193 GCS::Point aPoint1, aPoint2;
194 for (std::set<AttributePtr>::iterator aPIt = aCoincidentPoints.begin();
195 aPIt != aCoincidentPoints.end(); ++aPIt) {
196 if ((*aPIt)->owner() == aFeatures[i]) {
197 if ((*aPIt)->id() == SketchPlugin_BSpline::START_ID()) {
198 aPoint1 = aBSpline->poles[0];
199 aPoint2 = aBSpline->poles[1];
201 else if ((*aPIt)->id() == SketchPlugin_BSpline::END_ID()) {
202 aPoint1 = aBSpline->poles[aBSpline->poles.size() - 2];
203 aPoint2 = aBSpline->poles[aBSpline->poles.size() - 1];
209 // substitute B-spline by its boundary segment
210 std::shared_ptr<GCS::Line> aSegment(new GCS::Line);
211 aSegment->p1 = aPoint1;
212 aSegment->p2 = aPoint2;
213 aTgEntities[i] = EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aSegment));
220 EntityWrapperPtr aSharedPointEntity;
221 std::list<GCSConstraintPtr> anAuxConstraints;
222 if (!aCoincidentPoints.empty()) {
223 mySharedPoint = *aCoincidentPoints.begin();
224 aSharedPointEntity = myStorage->entity(mySharedPoint);
226 else if (aNbEllipses + aNbSplines > 0) {
227 // create auxiliary point
228 GCSPointPtr aPoint(new GCS::Point);
229 aPoint->x = aStorage->createParameter();
230 aPoint->y = aStorage->createParameter();
231 calculateTangencyPoint(aTgEntities[0], aTgEntities[1], aPoint);
233 myAuxPoint.reset(new PlaneGCSSolver_PointWrapper(aPoint));
234 aSharedPointEntity = myAuxPoint;
236 EntityWrapperPtr aDummy;
237 for (int i = 0; i < 2; ++i) {
238 // create auxiliary parameters for coincidence with B-spline
239 if (aTgEntities[i]->type() == ENTITY_BSPLINE)
240 myAuxParameters[i].reset(new PlaneGCSSolver_ScalarWrapper(aStorage->createParameter()));
242 // create auxiliary coincident constraints for tangency with ellipse
243 ConstraintWrapperPtr aCoincidence = PlaneGCSSolver_Tools::createConstraint(ConstraintPtr(),
244 CONSTRAINT_PT_ON_CURVE, myAuxParameters[i],
245 aSharedPointEntity, aDummy, aTgEntities[i], aDummy);
246 anAuxConstraints.insert(anAuxConstraints.end(),
247 aCoincidence->constraints().begin(), aCoincidence->constraints().end());
251 if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
252 mySolverConstraint = createArcLineTangency(aTgEntities[0], aTgEntities[1],
253 aSharedPointEntity, &myCurveCurveAngle);
255 mySolverConstraint = createCurveCurveTangency(aTgEntities[0], aTgEntities[1],
256 isArcArcInternal, aSharedPointEntity, &myCurveCurveAngle);
259 if (!anAuxConstraints.empty()) {
260 anAuxConstraints.insert(anAuxConstraints.end(), mySolverConstraint->constraints().begin(),
261 mySolverConstraint->constraints().end());
262 mySolverConstraint->setConstraints(anAuxConstraints);
265 myStorage->addConstraint(myBaseConstraint, mySolverConstraint);
268 void SketchSolver_ConstraintTangent::adjustConstraint()
270 if (myType == CONSTRAINT_TANGENT_CURVE_CURVE) {
271 EntityWrapperPtr anEntity1 =
272 myStorage->entity(myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
273 EntityWrapperPtr anEntity2 =
274 myStorage->entity(myBaseConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
276 if (isArcArcInternal != isArcArcTangencyInternal(anEntity1, anEntity2))
281 void SketchSolver_ConstraintTangent::notify(const FeaturePtr& theFeature,
282 PlaneGCSSolver_Update* theUpdater)
284 if (theFeature->getKind() != SketchPlugin_ConstraintCoincidence::ID())
287 // base constraint may become invalid (for example, during undo)
288 if (!myBaseConstraint->data() || !myBaseConstraint->data()->isValid())
291 FeaturePtr aTgFeat1, aTgFeat2;
292 getTangentFeatures(myBaseConstraint, aTgFeat1, aTgFeat2);
294 bool isRebuild = false;
295 if (theFeature->data() && theFeature->data()->isValid()) {
296 // the constraint has been created
297 if (!mySharedPoint) {
298 // features has no shared point, check whether coincidence constraint binds these features)
299 int aNbCoincidentFeatures = 0;
300 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
301 AttributeRefAttrPtr aRefAttr = theFeature->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
306 if (aRefAttr->isObject())
307 anObj = aRefAttr->object();
309 anObj = aRefAttr->attr()->owner();
311 FeaturePtr aFeature = ModelAPI_Feature::feature(anObj);
312 if (aFeature == aTgFeat1 || aFeature == aTgFeat2)
313 ++aNbCoincidentFeatures;
316 if (aNbCoincidentFeatures == 2)
323 // The features are tangent in the shared point, but the coincidence has been removed/updated.
324 // Check if the coincidence is the same.
325 std::set<AttributePtr> aCoincidentPoints = coincidentBoundaryPoints(aTgFeat1, aTgFeat2);
327 std::set<AttributePtr>::iterator anIt = aCoincidentPoints.begin();
328 for (; anIt != aCoincidentPoints.end() && isRebuild; ++anIt)
329 if (*anIt == mySharedPoint)
330 isRebuild = false; // the coincidence is still exists => nothing to change
333 // check both features have a coincident point
334 std::set<AttributePtr> aCoincidentPoints = coincidentPoints(aTgFeat1, aTgFeat2);
335 isRebuild = (bool)(myAuxPoint.get()) == (!aCoincidentPoints.empty());
343 bool SketchSolver_ConstraintTangent::remove()
346 std::shared_ptr<PlaneGCSSolver_Storage> aStorage =
347 std::dynamic_pointer_cast<PlaneGCSSolver_Storage>(myStorage);
349 GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(myAuxPoint);
350 if (myAuxParameters[0])
351 aParams.insert(myAuxParameters[0]->scalar());
352 if (myAuxParameters[1])
353 aParams.insert(myAuxParameters[1]->scalar());
354 aStorage->removeParameters(aParams);
355 myAuxPoint = EntityWrapperPtr();
356 myAuxParameters[0] = myAuxParameters[1] = ScalarWrapperPtr();
358 return SketchSolver_Constraint::remove();
364 // ================== Auxiliary functions =================================
365 void getTangentFeatures(const ConstraintPtr& theConstraint,
366 FeaturePtr& theFeature1,
367 FeaturePtr& theFeature2)
369 AttributeRefAttrPtr aRefAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_A());
370 theFeature1 = ModelAPI_Feature::feature(aRefAttr->object());
371 aRefAttr = theConstraint->refattr(SketchPlugin_Constraint::ENTITY_B());
372 theFeature2 = ModelAPI_Feature::feature(aRefAttr->object());
375 std::set<FeaturePtr> collectCoincidences(FeaturePtr theFeature1, FeaturePtr theFeature2)
377 const std::set<AttributePtr>& aRefs1 = theFeature1->data()->refsToMe();
378 const std::set<AttributePtr>& aRefs2 = theFeature2->data()->refsToMe();
380 std::set<FeaturePtr> aCoincidences;
381 std::map<AttributePtr, FeaturePtr> aCoincidentPoints;
382 std::set<AttributePtr>::const_iterator anIt;
384 // collect coincidences referred to the first feature
385 for (anIt = aRefs1.begin(); anIt != aRefs1.end(); ++anIt) {
386 FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
387 if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
388 aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) {
389 aCoincidences.insert(aRef);
390 AttributeRefAttrPtr aRefAttrA = aRef->refattr(SketchPlugin_Constraint::ENTITY_A());
391 if (!aRefAttrA->isObject())
392 aCoincidentPoints[aRefAttrA->attr()] = aRef;
393 AttributeRefAttrPtr aRefAttrB = aRef->refattr(SketchPlugin_Constraint::ENTITY_B());
394 if (!aRefAttrB->isObject())
395 aCoincidentPoints[aRefAttrB->attr()] = aRef;
399 // leave only coincidences referred to the second feature
400 std::set<FeaturePtr> aCoincidencesBetweenFeatures;
401 for (anIt = aRefs2.begin(); anIt != aRefs2.end(); ++anIt) {
402 FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
403 if (aCoincidences.find(aRef) != aCoincidences.end())
404 aCoincidencesBetweenFeatures.insert(aRef);
405 else if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
406 aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID())) {
407 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
408 AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
409 if (aRefAttr && !aRefAttr->isObject()) {
410 std::map<AttributePtr, FeaturePtr>::iterator aFound =
411 aCoincidentPoints.find(aRefAttr->attr());
412 if (aFound != aCoincidentPoints.end()) {
413 aCoincidencesBetweenFeatures.insert(aRef);
414 aCoincidencesBetweenFeatures.insert(aFound->second);
421 return aCoincidencesBetweenFeatures;
424 std::set<AttributePtr> coincidentBoundaryPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
426 std::set<FeaturePtr> aCoincidences = collectCoincidences(theFeature1, theFeature2);
427 // collect points only
428 std::map<FeaturePtr, std::set<AttributePtr> > aCoincidentPoints;
429 std::set<FeaturePtr>::const_iterator aCIt = aCoincidences.begin();
430 for (; aCIt != aCoincidences.end(); ++ aCIt) {
431 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
432 AttributeRefAttrPtr aRefAttr = (*aCIt)->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
433 if (!aRefAttr || aRefAttr->isObject())
436 AttributePtr anAttr = aRefAttr->attr();
437 FeaturePtr anOwner = ModelAPI_Feature::feature(anAttr->owner());
438 if (anOwner == theFeature1 || anOwner == theFeature2) {
439 if (anAttr->id() == SketchPlugin_BSplineBase::POLES_ID()) {
440 AttributePoint2DArrayPtr aPoles =
441 std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anAttr);
443 AttributeIntegerPtr anIndex;
444 if (anOwner->getKind() == SketchPlugin_BSpline::ID()) {
445 anIndex = (*aCIt)->integer(i == 0 ?
446 SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A() :
447 SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
450 if (anIndex->value() == 0)
451 anAttr = anOwner->attribute(SketchPlugin_BSpline::START_ID());
452 else if (anIndex->value() + 1 == aPoles->size())
453 anAttr = anOwner->attribute(SketchPlugin_BSpline::END_ID());
455 aCoincidentPoints[anOwner].insert(anAttr);
458 else if (anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
459 anAttr->id() != SketchPlugin_Circle::CENTER_ID())
460 aCoincidentPoints[anOwner].insert(anAttr);
465 std::set<AttributePtr> aBoundaryPoints;
466 if (aCoincidentPoints.size() == 2) {
467 for (std::map<FeaturePtr, std::set<AttributePtr> >::iterator anIt = aCoincidentPoints.begin();
468 anIt != aCoincidentPoints.end(); ++anIt)
469 aBoundaryPoints.insert(anIt->second.begin(), anIt->second.end());
471 return aBoundaryPoints;
474 static std::set<AttributePtr> refsToFeatureAndResults(FeaturePtr theFeature)
476 std::set<AttributePtr> aRefs = theFeature->data()->refsToMe();
477 const std::list<ResultPtr>& aResults = theFeature->results();
478 for (std::list<ResultPtr>::const_iterator anIt = aResults.begin();
479 anIt != aResults.end(); ++anIt) {
480 const std::set<AttributePtr>& aResRefs = (*anIt)->data()->refsToMe();
481 aRefs.insert(aResRefs.begin(), aResRefs.end());
486 // collect all points coincident with the feature
487 static std::set<AttributePtr> pointsOnFeature(FeaturePtr theFeature)
489 std::set<AttributePtr> aPoints;
491 std::set<AttributePtr> aRefs = refsToFeatureAndResults(theFeature);
492 for (std::set<AttributePtr>::const_iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
493 FeaturePtr aRef = ModelAPI_Feature::feature((*anIt)->owner());
494 if (aRef && (aRef->getKind() == SketchPlugin_ConstraintCoincidence::ID() ||
495 aRef->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID() ||
496 aRef->getKind() == SketchPlugin_ConstraintMiddle::ID())) {
497 for (int i = 0; i < CONSTRAINT_ATTR_SIZE; ++i) {
498 AttributeRefAttrPtr aRefAttr = aRef->refattr(SketchPlugin_Constraint::ATTRIBUTE(i));
500 AttributePtr anAttr = aRefAttr->attr();
501 if (anAttr && anAttr->id() != SketchPlugin_Arc::CENTER_ID() &&
502 anAttr->id() != SketchPlugin_Circle::CENTER_ID())
503 aPoints.insert(anAttr);
511 std::set<AttributePtr> coincidentPoints(FeaturePtr theFeature1, FeaturePtr theFeature2)
513 std::set<AttributePtr> aPointsOnF1 = pointsOnFeature(theFeature1);
514 std::set<AttributePtr> aPointsOnF2 = pointsOnFeature(theFeature2);
516 std::set<AttributePtr> aCommonPoints;
517 for (std::set<AttributePtr>::iterator anIt = aPointsOnF1.begin();
518 anIt != aPointsOnF1.end(); ++anIt)
519 if (aPointsOnF2.find(*anIt) != aPointsOnF2.end())
520 aCommonPoints.insert(*anIt);
521 return aCommonPoints;
524 bool isArcArcTangencyInternal(EntityWrapperPtr theArc1, EntityWrapperPtr theArc2)
526 std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(
527 GCS_EDGE_WRAPPER(theArc1)->entity());
528 std::shared_ptr<GCS::Circle> aCirc2 = std::dynamic_pointer_cast<GCS::Circle>(
529 GCS_EDGE_WRAPPER(theArc2)->entity());
531 if (!aCirc1 || !aCirc2)
534 double aDX = *(aCirc1->center.x) - *(aCirc2->center.x);
535 double aDY = *(aCirc1->center.y) - *(aCirc2->center.y);
536 double aDist = sqrt(aDX * aDX + aDY * aDY);
538 return (aDist < *(aCirc1->rad) || aDist < *(aCirc2->rad));
541 // sets angle to 0 or 180 degrees
542 static void adjustAngleBetweenCurves(const GCSCurvePtr& theCurve1,
543 const GCSCurvePtr& theCurve2,
544 const GCSPointPtr& thePoint,
547 double anAngle = GCS::System().calculateAngleViaPoint(*theCurve1, *theCurve2, *thePoint);
548 // bring angle to [-pi..pi]
549 if (anAngle > PI) anAngle -= 2.0 * PI;
550 if (anAngle < -PI) anAngle += 2.0 * PI;
551 // set angle value according to the current angle between curves
552 if (fabs(anAngle) <= PI / 2.)
559 ConstraintWrapperPtr createArcLineTangency(EntityWrapperPtr theEntity1,
560 EntityWrapperPtr theEntity2,
561 EntityWrapperPtr theSharedPoint,
564 EdgeWrapperPtr anEntLine, anEntCirc;
565 if (theEntity1->type() == ENTITY_LINE) {
566 anEntLine = GCS_EDGE_WRAPPER(theEntity1);
567 anEntCirc = GCS_EDGE_WRAPPER(theEntity2);
569 anEntLine = GCS_EDGE_WRAPPER(theEntity2);
570 anEntCirc = GCS_EDGE_WRAPPER(theEntity1);
573 std::shared_ptr<GCS::Circle> aCirc =
574 std::dynamic_pointer_cast<GCS::Circle>(anEntCirc->entity());
575 std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(aCirc);
577 std::shared_ptr<GCS::Line> aLine =
578 std::dynamic_pointer_cast<GCS::Line>(anEntLine->entity());
580 GCSConstraintPtr aNewConstr;
581 if (theSharedPoint && anArc) { // do not process shared point between circle and line
583 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
585 adjustAngleBetweenCurves(anArc, aLine, aPoint, theAngle);
587 GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*anArc, *aLine, *aPoint, theAngle));
590 GCSConstraintPtr(new GCS::ConstraintP2LDistance(aCirc->center, *aLine, aCirc->rad));
593 return ConstraintWrapperPtr(
594 new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CIRCLE_LINE));
597 ConstraintWrapperPtr createCurveCurveTangency(EntityWrapperPtr theEntity1,
598 EntityWrapperPtr theEntity2,
599 bool theInternalTangency,
600 EntityWrapperPtr theSharedPoint,
603 GCSCurvePtr aCurve1 =
604 std::dynamic_pointer_cast<GCS::Curve>(GCS_EDGE_WRAPPER(theEntity1)->entity());
605 GCSCurvePtr aCurve2 =
606 std::dynamic_pointer_cast<GCS::Curve>(GCS_EDGE_WRAPPER(theEntity2)->entity());
608 GCSConstraintPtr aNewConstr;
609 if (theSharedPoint) {
611 std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSharedPoint)->point();
613 adjustAngleBetweenCurves(aCurve1, aCurve2, aPoint, theAngle);
615 GCSConstraintPtr(new GCS::ConstraintAngleViaPoint(*aCurve1, *aCurve2, *aPoint, theAngle));
617 std::shared_ptr<GCS::Circle> aCirc1 = std::dynamic_pointer_cast<GCS::Circle>(aCurve1);
618 std::shared_ptr<GCS::Circle> aCirc2 = std::dynamic_pointer_cast<GCS::Circle>(aCurve2);
619 aNewConstr = GCSConstraintPtr(new GCS::ConstraintTangentCircumf(aCirc1->center, aCirc2->center,
620 aCirc1->rad, aCirc2->rad, theInternalTangency));
623 return ConstraintWrapperPtr(
624 new PlaneGCSSolver_ConstraintWrapper(aNewConstr, CONSTRAINT_TANGENT_CURVE_CURVE));
627 void calculateTangencyPoint(EntityWrapperPtr theCurve1, EntityWrapperPtr theCurve2,
628 GCSPointPtr& theTangencyPoint)
630 std::shared_ptr<GeomAPI_Ellipse2d> anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve1);
631 EntityWrapperPtr aCurve2 = theCurve2;
633 // try converting to ellipse the second curve
634 anEllipse = PlaneGCSSolver_Tools::ellipse(theCurve2);
636 return; // no one curve is ellipse
640 GeomPnt2dPtr aP1, aP2;
641 if (aCurve2->type() == ENTITY_LINE) {
642 std::shared_ptr<GeomAPI_Lin2d> aLine = PlaneGCSSolver_Tools::line(aCurve2);
643 anEllipse->distance(aLine, aP1, aP2);
645 else if (aCurve2->type() == ENTITY_ARC || aCurve2->type() == ENTITY_CIRCLE) {
646 std::shared_ptr<GeomAPI_Circ2d> aCircle = PlaneGCSSolver_Tools::circle(aCurve2);
647 anEllipse->distance(aCircle, aP1, aP2);
649 else if (aCurve2->type() == ENTITY_ELLIPSE || aCurve2->type() == ENTITY_ELLIPTIC_ARC) {
650 std::shared_ptr<GeomAPI_Ellipse2d> anEl2 = PlaneGCSSolver_Tools::ellipse(aCurve2);
651 anEllipse->distance(anEl2, aP1, aP2);
655 *theTangencyPoint->x = 0.5 * (aP1->x() + aP2->x());
656 *theTangencyPoint->y = 0.5 * (aP1->y() + aP2->y());