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