]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_Group.cpp
Salome HOME
Receive DoF from the solver. Update test cases to check DoF.
[modules/shaper.git] / src / SketchSolver / SketchSolver_Group.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:    SketchSolver_Group.cpp
4 // Created: 27 May 2014
5 // Author:  Artem ZHIDKOV
6
7 #include "SketchSolver_Group.h"
8 #include <SketchSolver_Error.h>
9 #include <SketchSolver_Manager.h>
10
11 #include <PlaneGCSSolver_Solver.h>
12
13 #include <Events_InfoMessage.h>
14 #include <ModelAPI_AttributeString.h>
15 #include <ModelAPI_Events.h>
16 #include <SketchPlugin_ConstraintRigid.h>
17
18
19 static void sendMessage(const char* theMessageName)
20 {
21   std::shared_ptr<Events_Message> aMessage = std::shared_ptr<Events_Message>(
22       new Events_Message(Events_Loop::eventByName(theMessageName)));
23   Events_Loop::loop()->send(aMessage);
24 }
25
26 static void sendMessage(const char* theMessageName, const std::set<ObjectPtr>& theConflicting)
27 {
28   std::shared_ptr<ModelAPI_SolverFailedMessage> aMessage =
29       std::shared_ptr<ModelAPI_SolverFailedMessage>(
30       new ModelAPI_SolverFailedMessage(Events_Loop::eventByName(theMessageName)));
31   aMessage->setObjects(theConflicting);
32   Events_Loop::loop()->send(aMessage);
33 }
34
35
36
37 // ========================================================
38 // =========  SketchSolver_Group  ===============
39 // ========================================================
40
41 SketchSolver_Group::SketchSolver_Group(const CompositeFeaturePtr& theWorkplane)
42   : mySketch(theWorkplane),
43     myPrevResult(STATUS_UNKNOWN),
44     myIsEventsBlocked(false)
45 {
46   BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
47   mySketchSolver = aBuilder->createSolver();
48   myStorage = aBuilder->createStorage(mySketchSolver);
49 }
50
51 SketchSolver_Group::~SketchSolver_Group()
52 {
53   myConstraints.clear();
54   // send the message that there is no more conflicting constraints
55   if (!myConflictingConstraints.empty()) {
56     sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
57     myConflictingConstraints.clear();
58   }
59 }
60
61 // ============================================================================
62 //  Function: changeConstraint
63 //  Class:    SketchSolver_Group
64 //  Purpose:  create/update the constraint in the group
65 // ============================================================================
66 bool SketchSolver_Group::changeConstraint(
67     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
68 {
69   bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end();
70   if (isNewConstraint) {
71     BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
72     // Add constraint to the current group
73     SolverConstraintPtr aConstraint = aBuilder->createConstraint(theConstraint);
74     if (!aConstraint)
75       return false;
76     aConstraint->process(myStorage, myIsEventsBlocked);
77     if (!aConstraint->error().empty()) {
78       if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
79         return false; // some attribute are not initialized yet, don't show message
80       Events_InfoMessage("SketchSolver_Group", aConstraint->error(), this).send();
81     }
82     myConstraints[theConstraint] = aConstraint;
83   }
84   else
85     myConstraints[theConstraint]->update();
86   return true;
87 }
88
89 bool SketchSolver_Group::updateFeature(FeaturePtr theFeature)
90 {
91   return myStorage->update(theFeature);
92 }
93
94 bool SketchSolver_Group::moveFeature(FeaturePtr theFeature)
95 {
96   BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
97
98   // Create temporary Fixed constraint
99   SolverConstraintPtr aConstraint = aBuilder->createMovementConstraint(theFeature);
100   if (!aConstraint)
101     return false;
102   aConstraint->process(myStorage, myIsEventsBlocked);
103   if (aConstraint->error().empty())
104     setTemporary(aConstraint);
105   else
106     myStorage->notify(theFeature);
107
108   return true;
109 }
110
111 // ============================================================================
112 //  Function: resolveConstraints
113 //  Class:    SketchSolver_Group
114 //  Purpose:  solve the set of constraints for the current group
115 // ============================================================================
116 bool SketchSolver_Group::resolveConstraints()
117 {
118   bool aResolved = false;
119   bool isGroupEmpty = isEmpty() && myStorage->isEmpty();
120   if (myStorage->isNeedToResolve() &&
121       (!isGroupEmpty || !myConflictingConstraints.empty() || myPrevResult == STATUS_FAILED)) {
122 ////    if (!mySketchSolver)
123 ////      mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver();
124
125 ////    mySketchSolver->calculateFailedConstraints(false);
126 ////    myStorage->initializeSolver();
127 ////    mySketchSolver->prepare();
128
129     SketchSolver_SolveStatus aResult = STATUS_OK;
130     try {
131       if (!isGroupEmpty) {
132         // To avoid overconstraint situation, we will remove temporary constraints one-by-one
133         // and try to find the case without overconstraint
134         bool isLastChance = false;
135         while (true) {
136           aResult = mySketchSolver->solve();
137           if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET || isLastChance)
138             break;
139 ////          // try to update parameters and resolve once again
140 ////          ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin();
141 ////          for (; aConstrIt != myConstraints.end(); ++aConstrIt)
142 ////            aConstrIt->second->update();
143           isLastChance = true;
144
145           removeTemporaryConstraints();
146           mySketchSolver->calculateFailedConstraints(true); // something failed => need to find it
147 ////          myStorage->initializeSolver();
148         }
149       }
150     } catch (...) {
151 //      Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this);
152       getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
153         ->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
154       if (myPrevResult == STATUS_OK || myPrevResult == STATUS_UNKNOWN) {
155         // the error message should be changed before sending the message
156         sendMessage(EVENT_SOLVER_FAILED);
157         myPrevResult = STATUS_FAILED;
158       }
159       mySketchSolver->undo();
160       return false;
161     }
162     // solution succeeded, store results into correspondent attributes
163     if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) {
164       myStorage->setNeedToResolve(false);
165       myStorage->refresh();
166 ////      updateMultiConstraints(myConstraints);
167 ////      // multi-constraints updated some parameters, need to store them
168 ////      if (myStorage->isNeedToResolve())
169 ////        resolveConstraints();
170
171       if (myPrevResult != STATUS_OK || myPrevResult == STATUS_UNKNOWN) {
172         getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
173         std::set<ObjectPtr> aConflicting = myConflictingConstraints;
174         myConflictingConstraints.clear();
175         myPrevResult = STATUS_OK;
176         // the error message should be changed before sending the message
177         sendMessage(EVENT_SOLVER_REPAIRED, aConflicting);
178       }
179
180       // show degrees of freedom
181       computeDoF();
182     } else {
183       mySketchSolver->undo();
184       if (!myConstraints.empty()) {
185         // the error message should be changed before sending the message
186         getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
187           ->setValue(SketchSolver_Error::CONSTRAINTS());
188         if (myPrevResult != aResult ||
189             myPrevResult == STATUS_UNKNOWN ||
190             myPrevResult == STATUS_FAILED) {
191           // Obtain list of conflicting constraints
192           std::set<ObjectPtr> aConflicting = myStorage->getConflictingConstraints(mySketchSolver);
193
194           if (!myConflictingConstraints.empty()) {
195             std::set<ObjectPtr>::iterator anIt = aConflicting.begin();
196             for (; anIt != aConflicting.end(); ++anIt)
197               myConflictingConstraints.erase(*anIt);
198             if (!myConflictingConstraints.empty()) {
199               // some constraints does not conflict, send corresponding message
200               sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
201             }
202           }
203           myConflictingConstraints = aConflicting;
204           if (!myConflictingConstraints.empty())
205             sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints);
206           myPrevResult = aResult;
207         }
208       }
209     }
210
211     aResolved = true;
212   } else if (!isGroupEmpty) {
213     // Check if the group contains only constraints Fixed, update parameters by stored values
214     aResolved = true;
215     ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
216     for (; aCIt != myConstraints.end(); ++aCIt)
217       if (aCIt->first->getKind() != SketchPlugin_ConstraintRigid::ID()) {
218         aResolved = false;
219         break;
220       }
221     if (aCIt == myConstraints.end())
222       myStorage->refresh();
223   } else if (isGroupEmpty)
224     computeDoF();
225   removeTemporaryConstraints();
226   myStorage->setNeedToResolve(false);
227   return aResolved;
228 }
229
230 // ============================================================================
231 //  Function: computeDoF
232 //  Class:    SketchSolver_Group
233 //  Purpose:  compute DoF of the sketch and set corresponding field
234 // ============================================================================
235 void SketchSolver_Group::computeDoF() const
236 {
237   std::ostringstream aDoFMsg;
238   int aDoF = /*isEmpty() ? myStorage->numberOfParameters() :*/ mySketchSolver->dof();
239   if (aDoF == 0)
240     aDoFMsg << "Sketch is fully fixed (DoF = 0)";
241   else
242     aDoFMsg << "DoF (degrees of freedom) = " << aDoF;
243   mySketch->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aDoFMsg.str());
244 }
245
246 // ============================================================================
247 //  Function: repairConsistency
248 //  Class:    SketchSolver_Group
249 //  Purpose:  search removed entities and constraints
250 // ============================================================================
251 void SketchSolver_Group::repairConsistency()
252 {
253   if (!myStorage->isConsistent()) {
254     // remove invalid constraints
255     std::set<ConstraintPtr> anInvalidConstraints;
256     ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
257     for (; aCIter != myConstraints.end(); ++aCIter) {
258       if (!aCIter->first->data() || !aCIter->first->data()->isValid())
259         anInvalidConstraints.insert(aCIter->first);
260     }
261     std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
262     for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
263       removeConstraint(*aRemoveIt);
264
265     // remove invalid features
266     myStorage->removeInvalidEntities();
267
268     // show DoF
269     computeDoF();
270   }
271 }
272
273 // ============================================================================
274 //  Function: removeTemporaryConstraints
275 //  Class:    SketchSolver_Group
276 //  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
277 //            resolving the set of constraints
278 // ============================================================================
279 void SketchSolver_Group::removeTemporaryConstraints()
280 {
281   if (!myTempConstraints.empty()) {
282     std::dynamic_pointer_cast<PlaneGCSSolver_Solver>(
283         mySketchSolver)->removeConstraint(CID_MOVEMENT);
284
285     std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
286     for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
287       (*aTmpIt)->remove();
288
289     myTempConstraints.clear();
290   }
291
292   myStorage->setNeedToResolve(false);
293 }
294
295 // ============================================================================
296 //  Function: removeConstraint
297 //  Class:    SketchSolver_Group
298 //  Purpose:  remove constraint and all unused entities
299 // ============================================================================
300 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
301 {
302   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
303   for (; aCIter != myConstraints.end(); aCIter++)
304     if (aCIter->first == theConstraint) {
305       aCIter->second->remove(); // the constraint is not fully removed
306       break;
307     }
308   if (aCIter != myConstraints.end())
309     myConstraints.erase(aCIter);
310 }
311
312 // ============================================================================
313 //  Function: setTemporary
314 //  Class:    SketchSolver_Group
315 //  Purpose:  append given constraint to the group of temporary constraints
316 // ============================================================================
317 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
318 {
319   myTempConstraints.insert(theConstraint);
320 }
321
322 // ============================================================================
323 //  Function: blockEvents
324 //  Class:    SketchSolver_Group
325 //  Purpose:  block or unblock events from features in this group
326 // ============================================================================
327 void SketchSolver_Group::blockEvents(bool isBlocked)
328 {
329   if (myIsEventsBlocked == isBlocked)
330     return;
331
332   // block/unblock events from the features in the storage
333   myStorage->blockEvents(isBlocked);
334
335   // block/unblock events from constraints
336   ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
337   for (; aCIt != myConstraints.end(); ++aCIt)
338     aCIt->second->blockEvents(isBlocked);
339
340   myIsEventsBlocked = isBlocked;
341 }