Salome HOME
8360d0af506e3b6bba29f32b9ce5daf3c42e187b
[modules/shaper.git] / src / SketchSolver / SketchSolver_Constraint.cpp
1 // File:    SketchSolver_Constraint.cpp
2 // Created: 27 May 2014
3 // Author:  Artem ZHIDKOV
4
5 #include "SketchSolver_Constraint.h"
6 #include <SketchSolver_Solver.h>
7
8 #include <SketchPlugin_Line.h>
9 #include <SketchPlugin_Point.h>
10 #include <SketchPlugin_Circle.h>
11 #include <SketchPlugin_Arc.h>
12 #include <SketchPlugin_ConstraintCoincidence.h>
13 #include <SketchPlugin_ConstraintDistance.h>
14 #include <SketchPlugin_ConstraintLength.h>
15 #include <SketchPlugin_ConstraintParallel.h>
16 #include <SketchPlugin_ConstraintPerpendicular.h>
17 #include <SketchPlugin_ConstraintRadius.h>
18
19 #include <ModelAPI_AttributeRefAttr.h>
20 #include <ModelAPI_Data.h>
21 #include <ModelAPI_Document.h>
22 #include <ModelAPI_Object.h>
23 #include <ModelAPI_ResultConstruction.h>
24
25 #include <GeomDataAPI_Point.h>
26 #include <GeomDataAPI_Point2D.h>
27 #include <GeomAPI_Edge.h>
28 #include <GeomAPI_Shape.h>
29
30 /// Possible types of attributes (used to determine constraint type)
31 enum AttrType
32 {
33   UNKNOWN,  // Something wrong during type determination
34   POINT2D,
35   POINT3D,
36   LINE,
37   CIRCLE,
38   ARC
39 };
40
41 /// Calculate type of the attribute
42 static AttrType typeOfAttribute(boost::shared_ptr<ModelAPI_Attribute> theAttribute);
43
44 SketchSolver_Constraint::SketchSolver_Constraint()
45     : myConstraint(boost::shared_ptr<SketchPlugin_Constraint>()),
46       myType(SLVS_C_UNKNOWN),
47       myAttributesList()
48 {
49 }
50
51 SketchSolver_Constraint::SketchSolver_Constraint(
52     boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
53     : myConstraint(theConstraint),
54       myAttributesList()
55 {
56   myType = getType(myConstraint);
57 }
58
59 const int& SketchSolver_Constraint::getType(
60     boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
61 {
62   myType = SLVS_C_UNKNOWN;
63   if (!theConstraint)
64     return getType();
65
66   DataPtr aConstrData = theConstraint->data();
67   if (!aConstrData || !aConstrData->isValid())
68     return getType();
69
70   // Assign empty names of attributes
71   myAttributesList.clear();
72   for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++)
73     myAttributesList.push_back(std::string());
74
75   const std::string& aConstraintKind = theConstraint->getKind();
76   // Constraint for coincidence of two points
77   if (aConstraintKind.compare(SketchPlugin_ConstraintCoincidence::ID()) == 0) {
78     int anAttrPos = 0;
79     // Verify the constraint has only two attributes and they are points
80     int aPt2d = 0;  // bit-mapped field, each bit indicates whether the attribute is 2D point
81     int aPt3d = 0;  // bit-mapped field, the same information for 3D points
82     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
83       boost::shared_ptr<ModelAPI_Attribute> anAttr = 
84           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
85       if (!anAttr)
86         continue;
87       switch (typeOfAttribute(anAttr)) {
88         case POINT2D:  // the attribute is a 2D point
89           aPt2d |= (1 << indAttr);
90           myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
91           break;
92         case POINT3D:  // the attribute is a 3D point
93           aPt3d |= (1 << indAttr);
94           myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
95           break;
96         default:
97           // Attribute neither 2D nor 3D point is not supported by this type of constraint
98           return getType();
99       }
100     }
101     // The constrained points should be in first and second positions,
102     // so the expected value of aPt2d or aPt3d is 3
103     if ((aPt2d == 3 && aPt3d == 0) || (aPt2d == 0 && aPt3d == 3))
104       myType = SLVS_C_POINTS_COINCIDENT;
105     // Constraint parameters are wrong
106     return getType();
107   }
108
109   // Constraint for distance between point and another entity
110   if (aConstraintKind.compare(SketchPlugin_ConstraintDistance::ID()) == 0) {
111     int aNbPoints = 0;
112     int aNbEntities = 0;
113     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
114       boost::shared_ptr<ModelAPI_Attribute> anAttr = 
115           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
116       switch (typeOfAttribute(anAttr)) {
117         case POINT2D:
118         case POINT3D:
119           myAttributesList[aNbPoints++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
120           break;
121         case LINE:
122           // entities are placed starting from SketchPlugin_Constraint::ENTITY_C() attribute
123           myAttributesList[2 + aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
124           myType = SLVS_C_PT_LINE_DISTANCE;
125           break;
126       }
127     }
128     // Verify the correctness of constraint arguments
129     if (aNbPoints == 2 && aNbEntities == 0)
130       myType = SLVS_C_PT_PT_DISTANCE;
131     else if (aNbPoints != 1 || aNbEntities != 1)
132       myType = SLVS_C_UNKNOWN;
133     return getType();
134   }
135
136   // Constraint for the given length of a line
137   if (aConstraintKind.compare(SketchPlugin_ConstraintLength::ID()) == 0) {
138     int aNbLines = 0;
139     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
140       boost::shared_ptr<ModelAPI_Attribute> anAttr = 
141           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
142       if (typeOfAttribute(anAttr) == LINE)
143         myAttributesList[aNbLines++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
144     }
145     if (aNbLines == 1)
146       myType = SLVS_C_PT_PT_DISTANCE;
147     return getType();
148   }
149
150   // Constraint for two parallel/perpendicular lines
151   bool isParallel = (aConstraintKind.compare(SketchPlugin_ConstraintParallel::ID()) == 0);
152   bool isPerpendicular = (aConstraintKind.compare(SketchPlugin_ConstraintPerpendicular::ID()) == 0);
153   if (isParallel || isPerpendicular) {
154     int aNbEntities = 2;  // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
155     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
156       boost::shared_ptr<ModelAPI_Attribute> anAttr = 
157           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
158       if (typeOfAttribute(anAttr) == LINE)
159         myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
160     }
161     if (aNbEntities == 4)
162       myType = isParallel ? SLVS_C_PARALLEL : SLVS_C_PERPENDICULAR;
163     return getType();
164   }
165
166   // Constraint for radius of a circle or an arc of circle
167   if (aConstraintKind.compare(SketchPlugin_ConstraintRadius::ID()) == 0) {
168     int aNbEntities = 2;  // lines in SolveSpace constraints should started from SketchPlugin_Constraint::ENTITY_C() attribute
169     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
170       boost::shared_ptr<ModelAPI_Attribute> anAttr = 
171           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
172       AttrType aType = typeOfAttribute(anAttr);
173       if (aType == CIRCLE || aType == ARC)
174         myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
175     }
176     if (aNbEntities == 3)
177       myType = SLVS_C_DIAMETER;
178     return getType();
179   }
180
181   /// \todo Implement other kind of constraints
182
183   return getType();
184 }
185
186 // ================= Auxiliary functions ==============================
187 AttrType typeOfAttribute(boost::shared_ptr<ModelAPI_Attribute> theAttribute)
188 {
189   boost::shared_ptr<ModelAPI_AttributeRefAttr> anAttrRef = boost::dynamic_pointer_cast<
190       ModelAPI_AttributeRefAttr>(theAttribute);
191   if (!anAttrRef)
192     return UNKNOWN;
193
194   if (anAttrRef->isObject()) {
195     ResultConstructionPtr aRC = boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
196         anAttrRef->object());
197     if (!aRC || !aRC->shape())
198       return UNKNOWN;
199
200     if (aRC->shape()->isVertex())
201       return POINT3D;
202     else if (aRC->shape()->isEdge()) {
203       boost::shared_ptr<GeomAPI_Edge> anEdge = boost::dynamic_pointer_cast<GeomAPI_Edge>(
204           aRC->shape());
205       if (anEdge->isLine())
206         return LINE;
207       else if (anEdge->isCircle())
208         return CIRCLE;
209       else if (anEdge->isArc())
210         return ARC;
211     }
212   } else {
213     const std::string aType = anAttrRef->attr()->attributeType();
214     if (aType == GeomDataAPI_Point2D::type())
215       return POINT2D;
216     if (aType == GeomDataAPI_Point2D::type())
217       return POINT2D;
218   }
219
220   return UNKNOWN;
221 }
222