1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: SketchSolver_Group.cpp
4 // Created: 27 May 2014
5 // Author: Artem ZHIDKOV
7 #include "SketchSolver_Group.h"
8 #include <SketchSolver_Error.h>
9 #include <SketchSolver_Manager.h>
11 #include <PlaneGCSSolver_Solver.h>
12 #include <PlaneGCSSolver_Storage.h>
13 #include <PlaneGCSSolver_Tools.h>
15 #include <Events_InfoMessage.h>
16 #include <ModelAPI_AttributeString.h>
17 #include <ModelAPI_Events.h>
18 #include <SketchPlugin_ConstraintRigid.h>
21 static void sendMessage(const char* theMessageName)
23 std::shared_ptr<Events_Message> aMessage = std::shared_ptr<Events_Message>(
24 new Events_Message(Events_Loop::eventByName(theMessageName)));
25 Events_Loop::loop()->send(aMessage);
28 static void sendMessage(const char* theMessageName, const std::set<ObjectPtr>& theConflicting)
30 std::shared_ptr<ModelAPI_SolverFailedMessage> aMessage =
31 std::shared_ptr<ModelAPI_SolverFailedMessage>(
32 new ModelAPI_SolverFailedMessage(Events_Loop::eventByName(theMessageName)));
33 aMessage->setObjects(theConflicting);
34 Events_Loop::loop()->send(aMessage);
37 static void sendMessage(const char* theMessageName, const CompositeFeaturePtr& theSketch, const int theDOF)
39 std::shared_ptr<ModelAPI_SolverFailedMessage> aMessage =
40 std::shared_ptr<ModelAPI_SolverFailedMessage>(
41 new ModelAPI_SolverFailedMessage(Events_Loop::eventByName(theMessageName)));
43 std::set<ObjectPtr> anObjects;
44 anObjects.insert(theSketch);
45 aMessage->setObjects(anObjects);
46 aMessage->dof(theDOF);
48 Events_Loop::loop()->send(aMessage);
53 // ========================================================
54 // ========= SketchSolver_Group ===============
55 // ========================================================
57 SketchSolver_Group::SketchSolver_Group(const CompositeFeaturePtr& theWorkplane)
58 : mySketch(theWorkplane),
59 myPrevResult(PlaneGCSSolver_Solver::STATUS_UNKNOWN),
61 myIsEventsBlocked(false)
63 mySketchSolver = SolverPtr(new PlaneGCSSolver_Solver);
64 myStorage = StoragePtr(new PlaneGCSSolver_Storage(mySketchSolver));
67 SketchSolver_Group::~SketchSolver_Group()
69 myConstraints.clear();
70 // send the message that there is no more conflicting constraints
71 if (!myConflictingConstraints.empty()) {
72 sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
73 myConflictingConstraints.clear();
77 // ============================================================================
78 // Function: changeConstraint
79 // Class: SketchSolver_Group
80 // Purpose: create/update the constraint in the group
81 // ============================================================================
82 bool SketchSolver_Group::changeConstraint(
83 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
85 bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end();
86 if (isNewConstraint) {
87 // Add constraint to the current group
88 SolverConstraintPtr aConstraint = PlaneGCSSolver_Tools::createConstraint(theConstraint);
91 aConstraint->process(myStorage, myIsEventsBlocked);
92 if (!aConstraint->error().empty()) {
93 if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
94 return false; // some attribute are not initialized yet, don't show message
95 Events_InfoMessage("SketchSolver_Group", aConstraint->error(), this).send();
97 myConstraints[theConstraint] = aConstraint;
100 myConstraints[theConstraint]->update();
104 bool SketchSolver_Group::updateFeature(FeaturePtr theFeature)
106 return myStorage->update(theFeature);
109 bool SketchSolver_Group::moveFeature(FeaturePtr theFeature)
112 // avoid moving elements of fully constrained sketch
113 myStorage->refresh();
117 // Create temporary Fixed constraint
118 SolverConstraintPtr aConstraint = PlaneGCSSolver_Tools::createMovementConstraint(theFeature);
121 aConstraint->process(myStorage, myIsEventsBlocked);
122 if (aConstraint->error().empty())
123 setTemporary(aConstraint);
125 myStorage->notify(theFeature);
130 // ============================================================================
131 // Function: resolveConstraints
132 // Class: SketchSolver_Group
133 // Purpose: solve the set of constraints for the current group
134 // ============================================================================
135 bool SketchSolver_Group::resolveConstraints()
137 bool aResolved = false;
138 bool isGroupEmpty = isEmpty() && myStorage->isEmpty();
139 if (myStorage->isNeedToResolve() &&
140 (!isGroupEmpty || !myConflictingConstraints.empty() ||
141 myPrevResult == PlaneGCSSolver_Solver::STATUS_FAILED)) {
143 PlaneGCSSolver_Solver::SolveStatus aResult = PlaneGCSSolver_Solver::STATUS_OK;
146 aResult = mySketchSolver->solve();
148 getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
149 ->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
150 if (myPrevResult == PlaneGCSSolver_Solver::STATUS_OK ||
151 myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN) {
152 // the error message should be changed before sending the message
153 sendMessage(EVENT_SOLVER_FAILED);
154 myPrevResult = PlaneGCSSolver_Solver::STATUS_FAILED;
156 mySketchSolver->undo();
159 // solution succeeded, store results into correspondent attributes
160 if (aResult == PlaneGCSSolver_Solver::STATUS_OK ||
161 aResult == PlaneGCSSolver_Solver::STATUS_EMPTYSET) {
162 myStorage->setNeedToResolve(false);
163 myStorage->refresh();
164 //// updateMultiConstraints(myConstraints);
165 //// // multi-constraints updated some parameters, need to store them
166 //// if (myStorage->isNeedToResolve())
167 //// resolveConstraints();
169 if (myPrevResult != PlaneGCSSolver_Solver::STATUS_OK ||
170 myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN) {
171 getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
172 std::set<ObjectPtr> aConflicting = myConflictingConstraints;
173 myConflictingConstraints.clear();
174 myPrevResult = PlaneGCSSolver_Solver::STATUS_OK;
175 // the error message should be changed before sending the message
176 sendMessage(EVENT_SOLVER_REPAIRED, aConflicting);
179 // show degrees of freedom
182 mySketchSolver->undo();
183 if (!myConstraints.empty()) {
184 // the error message should be changed before sending the message
185 getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
186 ->setValue(SketchSolver_Error::CONSTRAINTS());
187 if (myPrevResult != aResult ||
188 myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN ||
189 myPrevResult == PlaneGCSSolver_Solver::STATUS_FAILED) {
190 // Obtain list of conflicting constraints
191 std::set<ObjectPtr> aConflicting = myStorage->getConflictingConstraints(mySketchSolver);
193 if (!myConflictingConstraints.empty()) {
194 std::set<ObjectPtr>::iterator anIt = aConflicting.begin();
195 for (; anIt != aConflicting.end(); ++anIt)
196 myConflictingConstraints.erase(*anIt);
197 if (!myConflictingConstraints.empty()) {
198 // some constraints does not conflict, send corresponding message
199 sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
202 myConflictingConstraints = aConflicting;
203 if (!myConflictingConstraints.empty())
204 sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints);
205 myPrevResult = aResult;
211 } else if (!isGroupEmpty) {
212 // Check if the group contains only constraints Fixed, update parameters by stored values
214 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
215 for (; aCIt != myConstraints.end(); ++aCIt)
216 if (aCIt->first->getKind() != SketchPlugin_ConstraintRigid::ID()) {
220 if (aCIt == myConstraints.end())
221 myStorage->refresh();
222 } else if (isGroupEmpty && isWorkplaneValid())
224 removeTemporaryConstraints();
225 myStorage->setNeedToResolve(false);
229 // ============================================================================
230 // Function: computeDoF
231 // Class: SketchSolver_Group
232 // Purpose: compute DoF of the sketch and set corresponding field
233 // ============================================================================
234 void SketchSolver_Group::computeDoF()
236 std::ostringstream aDoFMsg;
237 int aDoF = mySketchSolver->dof();
239 aDoFMsg << "Sketch is fully fixed (DoF = 0)";
241 aDoFMsg << "DoF (degrees of freedom) = " << aDoF;
242 mySketch->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aDoFMsg.str());
244 if (aDoF > 0 && myDOF == 0)
245 sendMessage(EVENT_SKETCH_UNDER_CONSTRAINED, mySketch, aDoF);
246 else if (aDoF == 0 && myDOF > 0)
247 sendMessage(EVENT_SKETCH_FULLY_CONSTRAINED, mySketch, aDoF);
249 sendMessage(EVENT_SKETCH_OVER_CONSTRAINED, mySketch, aDoF);
254 // ============================================================================
255 // Function: repairConsistency
256 // Class: SketchSolver_Group
257 // Purpose: search removed entities and constraints
258 // ============================================================================
259 void SketchSolver_Group::repairConsistency()
261 if (!myStorage->isConsistent()) {
262 // remove invalid constraints
263 std::set<ConstraintPtr> anInvalidConstraints;
264 ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
265 for (; aCIter != myConstraints.end(); ++aCIter) {
266 if (!aCIter->first->data() || !aCIter->first->data()->isValid())
267 anInvalidConstraints.insert(aCIter->first);
269 std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
270 for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
271 removeConstraint(*aRemoveIt);
273 // remove invalid features
274 myStorage->removeInvalidEntities();
281 // ============================================================================
282 // Function: removeTemporaryConstraints
283 // Class: SketchSolver_Group
284 // Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
285 // resolving the set of constraints
286 // ============================================================================
287 void SketchSolver_Group::removeTemporaryConstraints()
289 if (!myTempConstraints.empty()) {
290 mySketchSolver->removeConstraint(CID_MOVEMENT);
292 std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
293 for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
296 myTempConstraints.clear();
299 myStorage->setNeedToResolve(false);
302 // ============================================================================
303 // Function: removeConstraint
304 // Class: SketchSolver_Group
305 // Purpose: remove constraint and all unused entities
306 // ============================================================================
307 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
309 ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
310 for (; aCIter != myConstraints.end(); aCIter++)
311 if (aCIter->first == theConstraint) {
312 aCIter->second->remove(); // the constraint is not fully removed
315 if (aCIter != myConstraints.end())
316 myConstraints.erase(aCIter);
319 // ============================================================================
320 // Function: setTemporary
321 // Class: SketchSolver_Group
322 // Purpose: append given constraint to the group of temporary constraints
323 // ============================================================================
324 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
326 myTempConstraints.insert(theConstraint);
329 // ============================================================================
330 // Function: blockEvents
331 // Class: SketchSolver_Group
332 // Purpose: block or unblock events from features in this group
333 // ============================================================================
334 void SketchSolver_Group::blockEvents(bool isBlocked)
336 if (myIsEventsBlocked == isBlocked)
339 // block/unblock events from the features in the storage
340 myStorage->blockEvents(isBlocked);
342 // block/unblock events from constraints
343 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
344 for (; aCIt != myConstraints.end(); ++aCIt)
345 aCIt->second->blockEvents(isBlocked);
347 myIsEventsBlocked = isBlocked;