1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: SketchSolver_Constraint.cpp
4 // Created: 27 May 2014
5 // Author: Artem ZHIDKOV
7 #include "SketchSolver_Constraint.h"
8 #include <SketchSolver_Solver.h>
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>
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>
35 #include <GeomDataAPI_Point.h>
36 #include <GeomDataAPI_Point2D.h>
37 #include <GeomAPI_Edge.h>
38 #include <GeomAPI_Shape.h>
40 /// Possible types of attributes (used to determine constraint type)
43 UNKNOWN, // Something wrong during type determination
51 /// Calculate type of the attribute
52 static AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute);
54 SketchSolver_Constraint::SketchSolver_Constraint()
55 : myConstraint(std::shared_ptr<SketchPlugin_Constraint>()),
56 myType(SLVS_C_UNKNOWN),
61 SketchSolver_Constraint::SketchSolver_Constraint(
62 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
63 : myConstraint(theConstraint),
66 myType = getType(myConstraint);
69 const int& SketchSolver_Constraint::getType(
70 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
72 myType = SLVS_C_UNKNOWN;
76 DataPtr aConstrData = theConstraint->data();
77 if (!aConstrData || !aConstrData->isValid())
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());
85 const std::string& aConstraintKind = theConstraint->getKind();
86 // Constraint for coincidence of two points
87 if (aConstraintKind.compare(SketchPlugin_ConstraintCoincidence::ID()) == 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));
97 switch (typeOfAttribute(anAttr)) {
98 case POINT2D: // the attribute is a 2D point
99 aPt2d |= (1 << indAttr);
100 myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
102 case POINT3D: // the attribute is a 3D point
103 aPt3d |= (1 << indAttr);
104 myAttributesList[anAttrPos++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
107 // Attribute neither 2D nor 3D point is not supported by this type of constraint
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
119 // Constraint for distance between point and another entity
120 if (aConstraintKind.compare(SketchPlugin_ConstraintDistance::ID()) == 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)) {
129 myAttributesList[aNbPoints++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
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;
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;
146 // Constraint for the given length of a line
147 if (aConstraintKind.compare(SketchPlugin_ConstraintLength::ID()) == 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);
156 myType = SLVS_C_PT_PT_DISTANCE;
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);
171 if (aNbEntities == 4)
172 myType = isParallel ? SLVS_C_PARALLEL : SLVS_C_PERPENDICULAR;
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);
186 if (aNbEntities == 3)
187 myType = SLVS_C_DIAMETER;
191 // Constraint for fixed entity
192 if (aConstraintKind.compare(SketchPlugin_ConstraintRigid::ID()) == 0) {
193 // Verify that only one entity is filled
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);
203 myType = SLVS_C_WHERE_DRAGGED;
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);
218 if (aNbEntities == 3)
219 myType = isHorizontal ? SLVS_C_HORIZONTAL : SLVS_C_VERTICAL;
223 if (aConstraintKind.compare(SketchPlugin_ConstraintEqual::ID()) == 0) {
224 static const int aConstrType[3] = {
226 SLVS_C_EQUAL_LINE_ARC_LEN,
227 SLVS_C_EQUAL_LENGTH_LINES
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);
236 myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
239 else if (aType == CIRCLE || aType == ARC)
240 myAttributesList[aNbEntities++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
242 if (aNbEntities == 4)
243 myType = aConstrType[aNbLines];
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);
261 if (anArcPos - anArcPosDefault + aLinePos - aLinePosDefault == 2)
262 myType = aLinePos > 3 ? SLVS_C_ARC_LINE_TANGENT : SLVS_C_CURVE_CURVE_TANGENT;
266 if (aConstraintKind.compare(SketchPlugin_ConstraintMirror::ID()) == 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)));
274 myAttributesList[aNbAttrs] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
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);
285 if (aNbAttrs == 2 && hasMirrorLine)
286 myType = SLVS_C_SYMMETRIC_LINE;
290 if (aConstraintKind.compare(SketchPlugin_ConstraintFillet::ID()) == 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)));
296 myAttributesList[aNbAttrs++] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
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);
306 myType = SLVS_C_FILLET;
310 /// \todo Implement other kind of constraints
315 // ================= Auxiliary functions ==============================
316 AttrType typeOfAttribute(std::shared_ptr<ModelAPI_Attribute> theAttribute)
318 std::shared_ptr<ModelAPI_AttributeRefAttr> anAttrRef = std::dynamic_pointer_cast<
319 ModelAPI_AttributeRefAttr>(theAttribute);
323 if (anAttrRef->isObject()) {
324 ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
325 anAttrRef->object());
326 if (!aRC || !aRC->shape())
329 if (aRC->shape()->isVertex())
331 else if (aRC->shape()->isEdge()) {
332 std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(
334 if (anEdge->isLine())
336 else if (anEdge->isCircle())
338 else if (anEdge->isArc())
342 if (anAttrRef->attr().get() != NULL) {
343 const std::string aType = anAttrRef->attr()->attributeType();
344 if (aType == GeomDataAPI_Point2D::typeId())
346 if (aType == GeomDataAPI_Point2D::typeId())