Salome HOME
Issue #1941 Split auxiliary line.
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintTangent.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 #include <SketchSolver_ConstraintTangent.h>
4 #include <SketchSolver_Error.h>
5 #include <SketchSolver_Manager.h>
6
7 #include <GeomAPI_Pnt2d.h>
8 #include <SketchPlugin_Circle.h>
9
10 #include <cmath>
11
12
13 /// \brief Check whether the entities has only one shared point
14 static bool hasSingleCoincidence(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2)
15 {
16   BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
17
18   const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
19   const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
20
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
25
26   int aNbCoinc = 0;
27   std::list<EntityWrapperPtr>::const_iterator anIt1, anIt2;
28   for (anIt1 = aStartIt1; anIt1 != aPoints1.end(); ++anIt1) {
29     if ((*anIt1)->type() != ENTITY_POINT)
30       continue;
31     std::shared_ptr<GeomAPI_Pnt2d> aPt1 = aBuilder->point(*anIt1);
32     for (anIt2 = aStartIt2; anIt2 != aPoints2.end(); ++anIt2) {
33       if ((*anIt2)->type() != ENTITY_POINT)
34         continue;
35       std::shared_ptr<GeomAPI_Pnt2d> aPt2 = aBuilder->point(*anIt2);
36       if (aPt1->distance(aPt2) < tolerance)
37         ++aNbCoinc;
38     }
39   }
40   return aNbCoinc == 1;
41 }
42
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)
46 {
47   BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
48   return aBuilder->isArcArcTangencyInternal(theEntity1, theEntity2);
49 }
50
51
52 void SketchSolver_ConstraintTangent::getAttributes(
53     double& theValue,
54     std::vector<EntityWrapperPtr>& theAttributes)
55 {
56   SketchSolver_Constraint::getAttributes(theValue, theAttributes);
57   if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) {
58     theAttributes.clear();
59     return;
60   }
61
62   // Check the quantity of entities of each type and their order (arcs first)
63   int aNbLines = 0;
64   int aNbArcs = 0;
65   int aNbCircles = 0;
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)
70       ++aNbLines;
71     else if ((*anEntIt)->type() == ENTITY_ARC) {
72       ++aNbArcs;
73       isSwap = aNbLines > 0;
74     }
75     else if ((*anEntIt)->type() == ENTITY_CIRCLE) {
76       ++aNbCircles;
77       isSwap = aNbLines > 0;
78     }
79   }
80
81   if (aNbArcs < 1 && aNbCircles < 1) {
82     myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
83     return;
84   }
85   if (aNbLines == 1) {
86     if (aNbArcs == 1)
87       myType = CONSTRAINT_TANGENT_ARC_LINE;
88     else if (aNbCircles == 1)
89       myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
90   }
91   else if (aNbArcs == 2) {
92     myType = CONSTRAINT_TANGENT_ARC_ARC;
93     isArcArcInternal = isInternalTangency(theAttributes[2], theAttributes[3]);
94   }
95   else {
96     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
97     return;
98   }
99
100   if (myType == CONSTRAINT_TANGENT_ARC_LINE &&
101       !hasSingleCoincidence(theAttributes[2], theAttributes[3]))
102     myErrorMsg = SketchSolver_Error::TANGENCY_FAILED();
103
104   if (isSwap) {
105     EntityWrapperPtr aTemp = theAttributes[2];
106     theAttributes[2] = theAttributes[3];
107     theAttributes[3] = aTemp;
108   }
109 }
110
111 void SketchSolver_ConstraintTangent::adjustConstraint()
112 {
113   if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
114     ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
115     AttributePtr aCircleCenter = aConstraint->entities().front()->baseAttribute();
116     if (!aCircleCenter)
117       return;
118     FeaturePtr aCircle = ModelAPI_Feature::feature(aCircleCenter->owner());
119     AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
120         aCircle->attribute(SketchPlugin_Circle::RADIUS_ID()));
121
122     if (fabs(aRadius->value()) == fabs(aConstraint->value()))
123       return;
124
125     aConstraint->setValue(aRadius->value());
126
127     // Adjust the sign of constraint value
128     BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
129     aBuilder->adjustConstraint(aConstraint);
130     myStorage->addConstraint(myBaseConstraint, aConstraint);
131   }
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
137       remove();
138       process();
139     }
140   }
141 }