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