1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 #include <SketchSolver_ConstraintTangent.h>
4 #include <SketchSolver_Error.h>
5 #include <SketchSolver_Manager.h>
7 #include <GeomAPI_Pnt2d.h>
8 #include <SketchPlugin_Circle.h>
13 /// \brief Check whether the entities has only one shared point
14 static bool hasSingleCoincidence(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2)
16 BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
18 const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
19 const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
21 std::list<EntityWrapperPtr>::const_iterator aStartIt1 = aPoints1.begin();
22 if (theEntity1->type() == ENTITY_ARC) ++aStartIt1; // skip center of arc
23 std::list<EntityWrapperPtr>::const_iterator aStartIt2 = aPoints2.begin();
24 if (theEntity2->type() == ENTITY_ARC) ++aStartIt2; // skip center of arc
27 std::list<EntityWrapperPtr>::const_iterator anIt1, anIt2;
28 for (anIt1 = aStartIt1; anIt1 != aPoints1.end(); ++anIt1) {
29 if ((*anIt1)->type() != ENTITY_POINT)
31 std::shared_ptr<GeomAPI_Pnt2d> aPt1 = aBuilder->point(*anIt1);
32 for (anIt2 = aStartIt2; anIt2 != aPoints2.end(); ++anIt2) {
33 if ((*anIt2)->type() != ENTITY_POINT)
35 std::shared_ptr<GeomAPI_Pnt2d> aPt2 = aBuilder->point(*anIt2);
36 if (aPt1->distance(aPt2) < tolerance)
43 /// \brief Check if two connected arcs have centers
44 /// in same direction relatively to connection point
45 static bool isInternalTangency(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2)
47 BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
48 return aBuilder->isArcArcTangencyInternal(theEntity1, theEntity2);
52 void SketchSolver_ConstraintTangent::getAttributes(
54 std::vector<EntityWrapperPtr>& theAttributes)
56 SketchSolver_Constraint::getAttributes(theValue, theAttributes);
57 if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) {
58 theAttributes.clear();
62 // Check the quantity of entities of each type and their order (arcs first)
66 bool isSwap = false; // whether need to swap arguments (arc goes before line)
67 std::vector<EntityWrapperPtr>::iterator anEntIt = theAttributes.begin() + 2;
68 for (; anEntIt != theAttributes.end(); ++anEntIt) {
69 if ((*anEntIt)->type() == ENTITY_LINE)
71 else if ((*anEntIt)->type() == ENTITY_ARC) {
73 isSwap = aNbLines > 0;
75 else if ((*anEntIt)->type() == ENTITY_CIRCLE) {
77 isSwap = aNbLines > 0;
81 if (aNbArcs < 1 && aNbCircles < 1) {
82 myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
87 myType = CONSTRAINT_TANGENT_ARC_LINE;
88 else if (aNbCircles == 1)
89 myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
91 else if (aNbArcs == 2) {
92 myType = CONSTRAINT_TANGENT_ARC_ARC;
93 isArcArcInternal = isInternalTangency(theAttributes[2], theAttributes[3]);
96 myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
100 if (myType == CONSTRAINT_TANGENT_ARC_LINE &&
101 !hasSingleCoincidence(theAttributes[2], theAttributes[3]))
102 myErrorMsg = SketchSolver_Error::TANGENCY_FAILED();
105 EntityWrapperPtr aTemp = theAttributes[2];
106 theAttributes[2] = theAttributes[3];
107 theAttributes[3] = aTemp;
111 void SketchSolver_ConstraintTangent::adjustConstraint()
113 if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
114 ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
115 AttributePtr aCircleCenter = aConstraint->entities().front()->baseAttribute();
118 FeaturePtr aCircle = ModelAPI_Feature::feature(aCircleCenter->owner());
119 AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
120 aCircle->attribute(SketchPlugin_Circle::RADIUS_ID()));
122 if (fabs(aRadius->value()) == fabs(aConstraint->value()))
125 aConstraint->setValue(aRadius->value());
127 // Adjust the sign of constraint value
128 BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
129 aBuilder->adjustConstraint(aConstraint);
130 myStorage->addConstraint(myBaseConstraint, aConstraint);
132 else if (myType == CONSTRAINT_TANGENT_ARC_ARC) {
133 ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
134 if (isArcArcInternal != isInternalTangency(
135 aConstraint->entities().front(), aConstraint->entities().back())) {
136 // fully rebuld constraint, because it is unable to access attributes of PlaneGCS constraint