Salome HOME
Fix incorrect DoF after dump-import loop (issue #1767)
[modules/shaper.git] / src / SketchSolver / SketchSolver_ConstraintTangent.cpp
1 #include <SketchSolver_ConstraintTangent.h>
2 #include <SketchSolver_Error.h>
3 #include <SketchSolver_Manager.h>
4
5 #include <GeomAPI_Pnt2d.h>
6 #include <SketchPlugin_Circle.h>
7
8 #include <cmath>
9
10
11 /// \brief Check whether the entities has only one shared point
12 static bool hasSingleCoincidence(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2)
13 {
14   BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
15
16   const std::list<EntityWrapperPtr>& aPoints1 = theEntity1->subEntities();
17   const std::list<EntityWrapperPtr>& aPoints2 = theEntity2->subEntities();
18
19   std::list<EntityWrapperPtr>::const_iterator aStartIt1 = aPoints1.begin();
20   if (theEntity1->type() == ENTITY_ARC) ++aStartIt1; // skip center of arc
21   std::list<EntityWrapperPtr>::const_iterator aStartIt2 = aPoints2.begin();
22   if (theEntity2->type() == ENTITY_ARC) ++aStartIt2; // skip center of arc
23
24   int aNbCoinc = 0;
25   std::list<EntityWrapperPtr>::const_iterator anIt1, anIt2;
26   for (anIt1 = aStartIt1; anIt1 != aPoints1.end(); ++anIt1) {
27     if ((*anIt1)->type() != ENTITY_POINT)
28       continue;
29     std::shared_ptr<GeomAPI_Pnt2d> aPt1 = aBuilder->point(*anIt1);
30     for (anIt2 = aStartIt2; anIt2 != aPoints2.end(); ++anIt2) {
31       if ((*anIt2)->type() != ENTITY_POINT)
32         continue;
33       std::shared_ptr<GeomAPI_Pnt2d> aPt2 = aBuilder->point(*anIt2);
34       if (aPt1->distance(aPt2) < tolerance)
35         ++aNbCoinc;
36     }
37   }
38   return aNbCoinc == 1;
39 }
40
41 /// \brief Check if two connected arcs have centers
42 ///        in same direction relatively to connection point
43 static bool isInternalTangency(EntityWrapperPtr theEntity1, EntityWrapperPtr theEntity2)
44 {
45   BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
46   return aBuilder->isArcArcTangencyInternal(theEntity1, theEntity2);
47 }
48
49
50 void SketchSolver_ConstraintTangent::getAttributes(
51     double& theValue,
52     std::vector<EntityWrapperPtr>& theAttributes)
53 {
54   SketchSolver_Constraint::getAttributes(theValue, theAttributes);
55   if (!myErrorMsg.empty() || !theAttributes[2] || !theAttributes[3]) {
56     theAttributes.clear();
57     return;
58   }
59
60   // Check the quantity of entities of each type and their order (arcs first)
61   int aNbLines = 0;
62   int aNbArcs = 0;
63   int aNbCircles = 0;
64   bool isSwap = false; // whether need to swap arguments (arc goes before line)
65   std::vector<EntityWrapperPtr>::iterator anEntIt = theAttributes.begin() + 2;
66   for (; anEntIt != theAttributes.end(); ++anEntIt) {
67     if ((*anEntIt)->type() == ENTITY_LINE)
68       ++aNbLines;
69     else if ((*anEntIt)->type() == ENTITY_ARC) {
70       ++aNbArcs;
71       isSwap = aNbLines > 0;
72     }
73     else if ((*anEntIt)->type() == ENTITY_CIRCLE) {
74       ++aNbCircles;
75       isSwap = aNbLines > 0;
76     }
77   }
78
79   if (aNbArcs < 1 && aNbCircles < 1) {
80     myErrorMsg = SketchSolver_Error::INCORRECT_TANGENCY_ATTRIBUTE();
81     return;
82   }
83   if (aNbLines == 1) {
84     if (aNbArcs == 1)
85       myType = CONSTRAINT_TANGENT_ARC_LINE;
86     else if (aNbCircles == 1)
87       myType = CONSTRAINT_TANGENT_CIRCLE_LINE;
88   }
89   else if (aNbArcs == 2) {
90     myType = CONSTRAINT_TANGENT_ARC_ARC;
91     isArcArcInternal = isInternalTangency(theAttributes[2], theAttributes[3]);
92   }
93   else {
94     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
95     return;
96   }
97
98   if (myType == CONSTRAINT_TANGENT_ARC_LINE && 
99       !hasSingleCoincidence(theAttributes[2], theAttributes[3]))
100     myErrorMsg = SketchSolver_Error::TANGENCY_FAILED();
101
102   if (isSwap) {
103     EntityWrapperPtr aTemp = theAttributes[2];
104     theAttributes[2] = theAttributes[3];
105     theAttributes[3] = aTemp;
106   }
107 }
108
109 void SketchSolver_ConstraintTangent::adjustConstraint()
110 {
111   if (myType == CONSTRAINT_TANGENT_CIRCLE_LINE) {
112     ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
113     AttributePtr aCircleCenter = aConstraint->entities().front()->baseAttribute();
114     if (!aCircleCenter)
115       return;
116     FeaturePtr aCircle = ModelAPI_Feature::feature(aCircleCenter->owner());
117     AttributeDoublePtr aRadius = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(
118         aCircle->attribute(SketchPlugin_Circle::RADIUS_ID()));
119
120     if (fabs(aRadius->value()) == fabs(aConstraint->value()))
121       return;
122
123     aConstraint->setValue(aRadius->value());
124
125     // Adjust the sign of constraint value
126     BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
127     aBuilder->adjustConstraint(aConstraint);
128     myStorage->addConstraint(myBaseConstraint, aConstraint);
129   }
130   else if (myType == CONSTRAINT_TANGENT_ARC_ARC) {
131     ConstraintWrapperPtr aConstraint = myStorage->constraint(myBaseConstraint).front();
132     if (isArcArcInternal != isInternalTangency(
133         aConstraint->entities().front(), aConstraint->entities().back())) {
134       // fully rebuld constraint, because it is unable to access attributes of PlaneGCS constraint
135       remove();
136       process();
137     }
138   }
139 }