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