Salome HOME
e4af2a0643970b1518b35cd344566ccaffdce20a
[modules/shaper.git] / src / SketchSolver / SketchSolver_Constraint.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    SketchSolver_Constraint.cpp
4 // Created: 27 May 2014
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchSolver_Constraint.h"
8 #include <SketchSolver_Solver.h>
9
10 #include <SketchPlugin_Line.h>
11 #include <SketchPlugin_Point.h>
12 #include <SketchPlugin_Circle.h>
13 #include <SketchPlugin_Arc.h>
14 #include <SketchPlugin_ConstraintCoincidence.h>
15 #include <SketchPlugin_ConstraintDistance.h>
16 #include <SketchPlugin_ConstraintEqual.h>
17 #include <SketchPlugin_ConstraintHorizontal.h>
18 #include <SketchPlugin_ConstraintLength.h>
19 #include <SketchPlugin_ConstraintParallel.h>
20 #include <SketchPlugin_ConstraintPerpendicular.h>
21 #include <SketchPlugin_ConstraintRadius.h>
22 #include <SketchPlugin_ConstraintRigid.h>
23 #include <SketchPlugin_ConstraintTangent.h>
24 #include <SketchPlugin_ConstraintVertical.h>
25
26 #include <ModelAPI_AttributeRefAttr.h>
27 #include <ModelAPI_Data.h>
28 #include <ModelAPI_Document.h>
29 #include <ModelAPI_Object.h>
30 #include <ModelAPI_ResultConstruction.h>
31
32 #include <GeomDataAPI_Point.h>
33 #include <GeomDataAPI_Point2D.h>
34 #include <GeomAPI_Edge.h>
35 #include <GeomAPI_Shape.h>
36
37 /// Possible types of attributes (used to determine constraint type)
38 enum AttrType
39 {
40   UNKNOWN,  // Something wrong during type determination
41   POINT2D,
42   POINT3D,
43   LINE,
44   CIRCLE,
45   ARC
46 };
47
48 /// Calculate type of the attribute
49 static AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute);
50
51 SketchSolver_Constraint::SketchSolver_Constraint()
52     : myConstraint(std::shared_ptr<SketchPlugin_Constraint>()),
53       myType(SLVS_C_UNKNOWN),
54       myAttributesList()
55 {
56 }
57
58 SketchSolver_Constraint::SketchSolver_Constraint(
59     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
60     : myConstraint(theConstraint),
61       myAttributesList()
62 {
63   myType = getType(myConstraint);
64 }
65
66 const int& SketchSolver_Constraint::getType(
67     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
68 {
69   myType = SLVS_C_UNKNOWN;
70   if (!theConstraint)
71     return getType();
72
73   DataPtr aConstrData = theConstraint->data();
74   if (!aConstrData || !aConstrData->isValid())
75     return getType();
76
77   // Assign empty names of attributes
78   myAttributesList.clear();
79   for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++)
80     myAttributesList.push_back(std::string());
81
82   const std::string& aConstraintKind = theConstraint->getKind();
83   // Constraint for coincidence of two points
84   if (aConstraintKind.compare(SketchPlugin_ConstraintCoincidence::ID()) == 0) {
85     int anAttrPos = 0;
86     // Verify the constraint has only two attributes and they are points
87     int aPt2d = 0;  // bit-mapped field, each bit indicates whether the attribute is 2D point
88     int aPt3d = 0;  // bit-mapped field, the same information for 3D points
89     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
90       std::shared_ptr<ModelAPI_Attribute> anAttr = 
91           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
92       if (!anAttr)
93         continue;
94       switch (typeOfAttribute(anAttr)) {
95         case POINT2D:  // the attribute is a 2D point
96           aPt2d |= (1 << indAttr);
97           myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
98           break;
99         case POINT3D:  // the attribute is a 3D point
100           aPt3d |= (1 << indAttr);
101           myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
102           break;
103         default:
104           // Attribute neither 2D nor 3D point is not supported by this type of constraint
105           return getType();
106       }
107     }
108     // The constrained points should be in first and second positions,
109     // so the expected value of aPt2d or aPt3d is 3
110     if ((aPt2d == 3 && aPt3d == 0) || (aPt2d == 0 && aPt3d == 3))
111       myType = SLVS_C_POINTS_COINCIDENT;
112     // Constraint parameters are wrong
113     return getType();
114   }
115
116   // Constraint for distance between point and another entity
117   if (aConstraintKind.compare(SketchPlugin_ConstraintDistance::ID()) == 0) {
118     int aNbPoints = 0;
119     int aNbEntities = 0;
120     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
121       std::shared_ptr<ModelAPI_Attribute> anAttr = 
122           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
123       switch (typeOfAttribute(anAttr)) {
124         case POINT2D:
125         case POINT3D:
126           myAttributesList[aNbPoints++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
127           break;
128         case LINE:
129           // entities are placed starting from SketchPlugin_Constraint::ENTITY_C() attribute
130           myAttributesList[2 + aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
131           myType = SLVS_C_PT_LINE_DISTANCE;
132           break;
133       }
134     }
135     // Verify the correctness of constraint arguments
136     if (aNbPoints == 2 && aNbEntities == 0)
137       myType = SLVS_C_PT_PT_DISTANCE;
138     else if (aNbPoints != 1 || aNbEntities != 1)
139       myType = SLVS_C_UNKNOWN;
140     return getType();
141   }
142
143   // Constraint for the given length of a line
144   if (aConstraintKind.compare(SketchPlugin_ConstraintLength::ID()) == 0) {
145     int aNbLines = 0;
146     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
147       std::shared_ptr<ModelAPI_Attribute> anAttr = 
148           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
149       if (typeOfAttribute(anAttr) == LINE)
150         myAttributesList[aNbLines++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
151     }
152     if (aNbLines == 1)
153       myType = SLVS_C_PT_PT_DISTANCE;
154     return getType();
155   }
156
157   // Constraint for two parallel/perpendicular lines
158   bool isParallel = (aConstraintKind.compare(SketchPlugin_ConstraintParallel::ID()) == 0);
159   bool isPerpendicular = (aConstraintKind.compare(SketchPlugin_ConstraintPerpendicular::ID()) == 0);
160   if (isParallel || isPerpendicular) {
161     int aNbEntities = 2;  // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
162     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
163       std::shared_ptr<ModelAPI_Attribute> anAttr = 
164           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
165       if (typeOfAttribute(anAttr) == LINE)
166         myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
167     }
168     if (aNbEntities == 4)
169       myType = isParallel ? SLVS_C_PARALLEL : SLVS_C_PERPENDICULAR;
170     return getType();
171   }
172
173   // Constraint for radius of a circle or an arc of circle
174   if (aConstraintKind.compare(SketchPlugin_ConstraintRadius::ID()) == 0) {
175     int aNbEntities = 2;  // lines in SolveSpace constraints should started from SketchPlugin_Constraint::ENTITY_C() attribute
176     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
177       std::shared_ptr<ModelAPI_Attribute> anAttr = 
178           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
179       AttrType aType = typeOfAttribute(anAttr);
180       if (aType == CIRCLE || aType == ARC)
181         myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
182     }
183     if (aNbEntities == 3)
184       myType = SLVS_C_DIAMETER;
185     return getType();
186   }
187
188   // Constraint for fixed entity
189   if (aConstraintKind.compare(SketchPlugin_ConstraintRigid::ID()) == 0) {
190     // Verify that only one entity is filled
191     int aNbAttrs = 0;
192     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
193       std::shared_ptr<ModelAPI_Attribute> anAttr = 
194           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
195       AttrType aType = typeOfAttribute(anAttr);
196       if (aType != UNKNOWN)
197         myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
198     }
199     if (aNbAttrs == 1)
200       myType = SLVS_C_WHERE_DRAGGED;
201     return getType();
202   }
203
204   // Constraint for horizontal/vertical line
205   bool isHorizontal = (aConstraintKind.compare(SketchPlugin_ConstraintHorizontal::ID()) == 0);
206   bool isVertical = (aConstraintKind.compare(SketchPlugin_ConstraintVertical::ID()) == 0);
207   if (isHorizontal || isVertical) {
208     int aNbEntities = 2;  // lines in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
209     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
210       std::shared_ptr<ModelAPI_Attribute> anAttr = 
211           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
212       if (typeOfAttribute(anAttr) == LINE)
213         myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
214     }
215     if (aNbEntities == 3)
216       myType = isHorizontal ? SLVS_C_HORIZONTAL : SLVS_C_VERTICAL;
217     return getType();
218   }
219
220   if (aConstraintKind.compare(SketchPlugin_ConstraintEqual::ID()) == 0)
221   {
222     static const int aConstrType[3] = {
223         SLVS_C_EQUAL_RADIUS,
224         SLVS_C_EQUAL_LINE_ARC_LEN,
225         SLVS_C_EQUAL_LENGTH_LINES
226     };
227     int aNbLines = 0;
228     int aNbEntities = 2;  // lines and circles in SolveSpace constraints should start from SketchPlugin_Constraint::ENTITY_C() attribute
229     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
230       std::shared_ptr<ModelAPI_Attribute> anAttr = 
231           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
232       AttrType aType = typeOfAttribute(anAttr);
233       if (aType == LINE) {
234         myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
235         aNbLines++;
236       }
237       else if (aType == CIRCLE || aType == ARC)
238         myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
239     }
240     if (aNbEntities == 4)
241       myType = aConstrType[aNbLines];
242     return getType();
243   }
244
245   if (aConstraintKind.compare(SketchPlugin_ConstraintTangent::ID()) == 0)
246   {
247     static const int anArcPosDefault = 2;
248     static const int aLinePosDefault = 3;
249     int anArcPos = anArcPosDefault; // arc in tangency constraint should be placed before line
250     int aLinePos = aLinePosDefault;
251     for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
252       std::shared_ptr<ModelAPI_Attribute> anAttr = 
253           aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
254       AttrType aType = typeOfAttribute(anAttr);
255       if (aType == LINE && aLinePos < CONSTRAINT_ATTR_SIZE)
256         myAttributesList[aLinePos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
257       else if (aType == ARC)
258         myAttributesList[anArcPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
259     }
260     if (anArcPos - anArcPosDefault + aLinePos - aLinePosDefault == 2)
261       myType = aLinePos > 3 ? SLVS_C_ARC_LINE_TANGENT : SLVS_C_CURVE_CURVE_TANGENT;
262     return getType();
263   }
264
265   /// \todo Implement other kind of constraints
266
267   return getType();
268 }
269
270 // ================= Auxiliary functions ==============================
271 AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute)
272 {
273   std::shared_ptr<ModelAPI_AttributeRefAttr> anAttrRef = std::dynamic_pointer_cast<
274       ModelAPI_AttributeRefAttr>(theAttribute);
275   if (!anAttrRef)
276     return UNKNOWN;
277
278   if (anAttrRef->isObject()) {
279     ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
280         anAttrRef->object());
281     if (!aRC || !aRC->shape())
282       return UNKNOWN;
283
284     if (aRC->shape()->isVertex())
285       return POINT3D;
286     else if (aRC->shape()->isEdge()) {
287       std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(
288           aRC->shape());
289       if (anEdge->isLine())
290         return LINE;
291       else if (anEdge->isCircle())
292         return CIRCLE;
293       else if (anEdge->isArc())
294         return ARC;
295     }
296   } else {
297     if (anAttrRef->attr().get() != NULL) {
298       const std::string aType = anAttrRef->attr()->attributeType();
299       if (aType == GeomDataAPI_Point2D::type())
300         return POINT2D;
301       if (aType == GeomDataAPI_Point2D::type())
302         return POINT2D;
303     }
304   }
305
306   return UNKNOWN;
307 }
308