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