1 // File: SketchSolver_ConstraintManager.cpp
2 // Created: 08 May 2014
3 // Author: Artem ZHIDKOV
5 #include "SketchSolver_ConstraintManager.h"
7 #include <Events_Loop.h>
8 #include <GeomDataAPI_Dir.h>
9 #include <GeomDataAPI_Point.h>
10 #include <GeomDataAPI_Point2D.h>
11 #include <ModelAPI_AttributeDouble.h>
12 #include <ModelAPI_AttributeRefList.h>
13 #include <ModelAPI_Data.h>
14 #include <Model_Events.h>
15 #include <SketchPlugin_Constraint.h>
16 #include <SketchPlugin_ConstraintCoincidence.h>
17 #include <SketchPlugin_Line.h>
18 #include <SketchPlugin_Sketch.h>
20 SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
22 /// Global constaint manager object
23 SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
25 /// This value is used to give unique index to the groups
26 static Slvs_hGroup myGroupIndexer = 0;
28 // ========================================================
29 // ========= SketchSolver_ConstraintManager ===============
30 // ========================================================
31 SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance()
34 _self = new SketchSolver_ConstraintManager();
38 SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
42 // Register in event loop
43 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
44 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
45 Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
48 SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
53 void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
55 if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED))
57 const Model_FeatureUpdatedMessage* aCreateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
59 // Only sketches and constraints can be added by Create event
60 boost::shared_ptr<SketchPlugin_Sketch> aSketch =
61 boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aCreateMsg->feature());
64 addWorkplane(aSketch);
67 boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
68 boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aCreateMsg->feature());
71 addConstraint(aConstraint);
75 else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
77 const Model_FeatureDeletedMessage* aDeleteMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
78 /// \todo Implement deleting objects on event
80 else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED))
82 const Model_FeatureUpdatedMessage* aUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
84 boost::shared_ptr<SketchPlugin_Sketch> aSketch =
85 boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aUpdateMsg->feature());
88 // updateWorkplane(aSketch);
92 boost::shared_ptr<SketchPlugin_Constraint> aConstraint =
93 boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aUpdateMsg->feature());
96 // updateConstraint(aConstraint);
100 boost::shared_ptr<SketchPlugin_Feature> aFeature =
101 boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
103 // updateEntity(aFeature);
108 bool SketchSolver_ConstraintManager::addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch)
110 // Check the specified workplane is already used
111 std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
112 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
113 if (aGroupIter->isBaseWorkplane(theSketch))
115 // Create new group for workplane
116 SketchSolver_ConstraintGroup aNewGroup(theSketch);
117 // Verify that the group is created successfully
118 if (!aNewGroup.isBaseWorkplane(theSketch))
120 myGroups.push_back(aNewGroup);
124 bool SketchSolver_ConstraintManager::addConstraint(
125 boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
127 // Search the groups which this constraint touchs
128 std::vector<Slvs_hGroup> aGroups;
129 findGroups(theConstraint, aGroups);
131 // Process the groups list
132 if (aGroups.size() == 0)
133 { // There are no groups applicable for this constraint => create new one
134 SketchSolver_ConstraintGroup aGroup(findWorkplaneForConstraint(theConstraint));
135 aGroup.addConstraint(theConstraint);
136 myGroups.push_back(aGroup);
138 else if (aGroups.size() == 1)
139 { // Only one group => add constraint into it
140 Slvs_hGroup aGroupId = *(aGroups.begin());
141 std::vector<SketchSolver_ConstraintGroup>::iterator aGroupIter;
142 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
143 if (aGroupIter->getId() == aGroupId)
144 return aGroupIter->addConstraint(theConstraint);
146 else if (aGroups.size() > 1)
147 { // Several groups applicable for this constraint => need to merge them
148 /// \todo Implement merging of groups
151 // Something goes wrong
156 void SketchSolver_ConstraintManager::findGroups(
157 boost::shared_ptr<SketchPlugin_Constraint> theConstraint,
158 std::vector<Slvs_hGroup>& theGroupIDs) const
160 std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
161 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
162 if (aGroupIter->isInteract(theConstraint))
163 theGroupIDs.push_back(aGroupIter->getId());
166 boost::shared_ptr<SketchPlugin_Sketch> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
167 boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
169 std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
170 for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
172 boost::shared_ptr<SketchPlugin_Sketch> aWP = aGroupIter->getWorkplane();
173 boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures =
174 boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SKETCH_ATTR_FEATURES));
175 std::list< boost::shared_ptr<ModelAPI_Feature> > aFeaturesList = aWPFeatures->list();
176 std::list< boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIter;
177 for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
178 if (*anIter == theConstraint)
179 return aWP; // workplane is found
182 return boost::shared_ptr<SketchPlugin_Sketch>();
187 // ========================================================
188 // ========= SketchSolver_ConstraintGroup ===============
189 // ========================================================
191 SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::
192 SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane)
193 : myID(++myGroupIndexer),
201 myConstraints.clear();
203 // Nullify all elements of the set of equations
204 myConstrSet.param = 0;
205 myConstrSet.entity = 0;
206 myConstrSet.constraint = 0;
207 myConstrSet.failed = 0;
209 // Initialize workplane
211 addWorkplane(theWorkplane);
214 SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
218 myConstraints.clear();
219 myConstraintMap.clear();
221 if (myConstrSet.param)
222 delete [] myConstrSet.param;
223 if (myConstrSet.entity)
224 delete [] myConstrSet.entity;
225 if (myConstrSet.constraint)
226 delete [] myConstrSet.constraint;
227 if (myConstrSet.failed)
228 delete [] myConstrSet.failed;
231 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isBaseWorkplane(
232 boost::shared_ptr<SketchPlugin_Sketch> theWorkplane) const
234 return theWorkplane == mySketch;
237 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract(
238 boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
240 /// \todo Should be implemented
244 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addConstraint(
245 boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
247 // There is no workplane yet, something wrong
248 if (myWorkplane.h == 0)
251 // Get constraint type and verify the constraint parameters are correct
252 int aConstrType = getConstraintType(theConstraint);
253 if (aConstrType == SLVS_C_UNKNOWN)
256 // Create constraint parameters
257 double aDistance = 0.0; // scalar value of the constraint
258 boost::shared_ptr<ModelAPI_AttributeDouble> aDistAttr =
259 boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
261 aDistance = aDistAttr->value();
263 Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
264 for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
266 boost::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr =
267 boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
268 theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
270 aConstrEnt[indAttr] = addEntity(aConstrAttr->attr());
273 // Create SolveSpace constraint structure
274 Slvs_Constraint aConstraint =
275 Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h,
276 aDistance, aConstrEnt[0], aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
277 myConstraints.push_back(aConstraint);
278 myConstraintMap[theConstraint] = *(myConstraints.rbegin());
283 Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addEntity(
284 boost::shared_ptr<ModelAPI_Attribute> theEntity)
286 // Look over supported types of entities
289 boost::shared_ptr<GeomDataAPI_Point> aPoint =
290 boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
293 Slvs_hParam aX = addParameter(aPoint->x());
294 Slvs_hParam aY = addParameter(aPoint->y());
295 Slvs_hParam aZ = addParameter(aPoint->z());
296 Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
297 myEntities.push_back(aPtEntity);
302 boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
303 boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
306 // The 2D points are created on workplane. So, if there is no workplane yet, then error
307 if (myWorkplane.h == 0)
309 Slvs_hParam aU = addParameter(aPoint2D->x());
310 Slvs_hParam aV = addParameter(aPoint2D->y());
311 Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
312 myEntities.push_back(aPt2DEntity);
313 return aPt2DEntity.h;
316 /// \todo Other types of entities
318 // Unsupported or wrong entity type
322 Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addNormal(
323 boost::shared_ptr<ModelAPI_Attribute> theDirX,
324 boost::shared_ptr<ModelAPI_Attribute> theDirY)
326 boost::shared_ptr<GeomDataAPI_Dir> aDirX = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirX);
327 boost::shared_ptr<GeomDataAPI_Dir> aDirY = boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theDirY);
328 if (!aDirX || !aDirY)
331 // quaternion parameters of normal vector
332 double qw, qx, qy, qz;
333 Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(),
334 aDirY->x(), aDirY->y(), aDirY->z(),
338 Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID,
339 addParameter(qw), addParameter(qx), addParameter(qy), addParameter(qz));
340 myEntities.push_back(aNormal);
345 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addWorkplane(
346 boost::shared_ptr<SketchPlugin_Sketch> theSketch)
349 return false; // the workplane already exists
351 // Get parameters of workplane
352 boost::shared_ptr<ModelAPI_Attribute> aDirX = theSketch->data()->attribute(SKETCH_ATTR_DIRX);
353 boost::shared_ptr<ModelAPI_Attribute> aDirY = theSketch->data()->attribute(SKETCH_ATTR_DIRY);
354 boost::shared_ptr<ModelAPI_Attribute> anOrigin = theSketch->data()->attribute(SKETCH_ATTR_ORIGIN);
355 // Transform them into SolveSpace format
356 Slvs_hEntity aNormalWP = addNormal(aDirX, aDirY);
357 if (!aNormalWP) return false;
358 Slvs_hEntity anOriginWP = addEntity(anOrigin);
359 if (!anOriginWP) return false;
361 myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
362 mySketch = theSketch;
363 // Workplane should be added to the list of entities
364 myEntities.push_back(myWorkplane);
368 Slvs_hParam SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addParameter(double theParam)
370 Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
371 myParams.push_back(aParam);
375 int SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::getConstraintType(
376 const boost::shared_ptr<SketchPlugin_Constraint>& theConstraint) const
378 // Constraint for coincidence of two points
379 boost::shared_ptr<SketchPlugin_ConstraintCoincidence> aPtEquiv =
380 boost::dynamic_pointer_cast<SketchPlugin_ConstraintCoincidence>(theConstraint);
383 // Verify the constraint has only two attributes and they are points
384 int aPt2d = 0; // bit-mapped field, each bit indicates whether the attribute is 2D point
385 int aPt3d = 0; // bit-mapped field, the same information for 3D points
386 for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
388 boost::shared_ptr<ModelAPI_AttributeRefAttr> anAttr =
389 boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
390 theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
392 // Verify the attribute is a 2D point
393 boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
394 boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
397 aPt2d |= (1 << indAttr);
400 // Verify the attribute is a 3D point
401 boost::shared_ptr<GeomDataAPI_Point> aPoint3D =
402 boost::dynamic_pointer_cast<GeomDataAPI_Point>(anAttr->attr());
405 aPt3d |= (1 << indAttr);
408 // Attribute neither 2D nor 3D point is not supported by this type of constraint
409 return SLVS_C_UNKNOWN;
411 // The constrained points should be in first and second positions,
412 // so the expected value of aPt2d or aPt3d is 3
413 if ((aPt2d == 3 && aPt3d == 0) || (aPt2d == 0 && aPt3d == 3))
414 return SLVS_C_POINTS_COINCIDENT;
415 // Constraint parameters are wrong
416 return SLVS_C_UNKNOWN;
419 /// \todo Implement other kind of constrtaints
421 return SLVS_C_UNKNOWN;