Salome HOME
Simplify sketcher model. Remove obsolete files and classes.
[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 #include <PlaneGCSSolver_Storage.h>
13 #include <PlaneGCSSolver_Tools.h>
14
15 #include <Events_InfoMessage.h>
16 #include <ModelAPI_AttributeString.h>
17 #include <ModelAPI_Events.h>
18 #include <SketchPlugin_ConstraintRigid.h>
19
20
21 static void sendMessage(const char* theMessageName)
22 {
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);
26 }
27
28 static void sendMessage(const char* theMessageName, const std::set<ObjectPtr>& theConflicting)
29 {
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);
35 }
36
37
38
39 // ========================================================
40 // =========  SketchSolver_Group  ===============
41 // ========================================================
42
43 SketchSolver_Group::SketchSolver_Group(const CompositeFeaturePtr& theWorkplane)
44   : mySketch(theWorkplane),
45     myPrevResult(PlaneGCSSolver_Solver::STATUS_UNKNOWN),
46     myIsEventsBlocked(false)
47 {
48   mySketchSolver = SolverPtr(new PlaneGCSSolver_Solver);
49   myStorage = StoragePtr(new PlaneGCSSolver_Storage(mySketchSolver));
50 }
51
52 SketchSolver_Group::~SketchSolver_Group()
53 {
54   myConstraints.clear();
55   // send the message that there is no more conflicting constraints
56   if (!myConflictingConstraints.empty()) {
57     sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
58     myConflictingConstraints.clear();
59   }
60 }
61
62 // ============================================================================
63 //  Function: changeConstraint
64 //  Class:    SketchSolver_Group
65 //  Purpose:  create/update the constraint in the group
66 // ============================================================================
67 bool SketchSolver_Group::changeConstraint(
68     std::shared_ptr<SketchPlugin_Constraint> theConstraint)
69 {
70   bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end();
71   if (isNewConstraint) {
72     // Add constraint to the current group
73     SolverConstraintPtr aConstraint = PlaneGCSSolver_Tools::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   // Create temporary Fixed constraint
97   SolverConstraintPtr aConstraint = PlaneGCSSolver_Tools::createMovementConstraint(theFeature);
98   if (!aConstraint)
99     return false;
100   aConstraint->process(myStorage, myIsEventsBlocked);
101   if (aConstraint->error().empty())
102     setTemporary(aConstraint);
103   else
104     myStorage->notify(theFeature);
105
106   return true;
107 }
108
109 // ============================================================================
110 //  Function: resolveConstraints
111 //  Class:    SketchSolver_Group
112 //  Purpose:  solve the set of constraints for the current group
113 // ============================================================================
114 bool SketchSolver_Group::resolveConstraints()
115 {
116   bool aResolved = false;
117   bool isGroupEmpty = isEmpty() && myStorage->isEmpty();
118   if (myStorage->isNeedToResolve() &&
119       (!isGroupEmpty || !myConflictingConstraints.empty() ||
120         myPrevResult == PlaneGCSSolver_Solver::STATUS_FAILED)) {
121
122     PlaneGCSSolver_Solver::SolveStatus aResult = PlaneGCSSolver_Solver::STATUS_OK;
123     try {
124       if (!isGroupEmpty)
125         aResult = mySketchSolver->solve();
126     } catch (...) {
127       getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
128         ->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
129       if (myPrevResult == PlaneGCSSolver_Solver::STATUS_OK ||
130           myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN) {
131         // the error message should be changed before sending the message
132         sendMessage(EVENT_SOLVER_FAILED);
133         myPrevResult = PlaneGCSSolver_Solver::STATUS_FAILED;
134       }
135       mySketchSolver->undo();
136       return false;
137     }
138     // solution succeeded, store results into correspondent attributes
139     if (aResult == PlaneGCSSolver_Solver::STATUS_OK ||
140         aResult == PlaneGCSSolver_Solver::STATUS_EMPTYSET) {
141       myStorage->setNeedToResolve(false);
142       myStorage->refresh();
143 ////      updateMultiConstraints(myConstraints);
144 ////      // multi-constraints updated some parameters, need to store them
145 ////      if (myStorage->isNeedToResolve())
146 ////        resolveConstraints();
147
148       if (myPrevResult != PlaneGCSSolver_Solver::STATUS_OK ||
149           myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN) {
150         getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
151         std::set<ObjectPtr> aConflicting = myConflictingConstraints;
152         myConflictingConstraints.clear();
153         myPrevResult = PlaneGCSSolver_Solver::STATUS_OK;
154         // the error message should be changed before sending the message
155         sendMessage(EVENT_SOLVER_REPAIRED, aConflicting);
156       }
157
158       // show degrees of freedom
159       computeDoF();
160     } else {
161       mySketchSolver->undo();
162       if (!myConstraints.empty()) {
163         // the error message should be changed before sending the message
164         getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
165           ->setValue(SketchSolver_Error::CONSTRAINTS());
166         if (myPrevResult != aResult ||
167             myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN ||
168             myPrevResult == PlaneGCSSolver_Solver::STATUS_FAILED) {
169           // Obtain list of conflicting constraints
170           std::set<ObjectPtr> aConflicting = myStorage->getConflictingConstraints(mySketchSolver);
171
172           if (!myConflictingConstraints.empty()) {
173             std::set<ObjectPtr>::iterator anIt = aConflicting.begin();
174             for (; anIt != aConflicting.end(); ++anIt)
175               myConflictingConstraints.erase(*anIt);
176             if (!myConflictingConstraints.empty()) {
177               // some constraints does not conflict, send corresponding message
178               sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
179             }
180           }
181           myConflictingConstraints = aConflicting;
182           if (!myConflictingConstraints.empty())
183             sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints);
184           myPrevResult = aResult;
185         }
186       }
187     }
188
189     aResolved = true;
190   } else if (!isGroupEmpty) {
191     // Check if the group contains only constraints Fixed, update parameters by stored values
192     aResolved = true;
193     ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
194     for (; aCIt != myConstraints.end(); ++aCIt)
195       if (aCIt->first->getKind() != SketchPlugin_ConstraintRigid::ID()) {
196         aResolved = false;
197         break;
198       }
199     if (aCIt == myConstraints.end())
200       myStorage->refresh();
201   } else if (isGroupEmpty)
202     computeDoF();
203   removeTemporaryConstraints();
204   myStorage->setNeedToResolve(false);
205   return aResolved;
206 }
207
208 // ============================================================================
209 //  Function: computeDoF
210 //  Class:    SketchSolver_Group
211 //  Purpose:  compute DoF of the sketch and set corresponding field
212 // ============================================================================
213 void SketchSolver_Group::computeDoF() const
214 {
215   std::ostringstream aDoFMsg;
216   int aDoF = /*isEmpty() ? myStorage->numberOfParameters() :*/ mySketchSolver->dof();
217   if (aDoF == 0)
218     aDoFMsg << "Sketch is fully fixed (DoF = 0)";
219   else
220     aDoFMsg << "DoF (degrees of freedom) = " << aDoF;
221   mySketch->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aDoFMsg.str());
222 }
223
224 // ============================================================================
225 //  Function: repairConsistency
226 //  Class:    SketchSolver_Group
227 //  Purpose:  search removed entities and constraints
228 // ============================================================================
229 void SketchSolver_Group::repairConsistency()
230 {
231   if (!myStorage->isConsistent()) {
232     // remove invalid constraints
233     std::set<ConstraintPtr> anInvalidConstraints;
234     ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
235     for (; aCIter != myConstraints.end(); ++aCIter) {
236       if (!aCIter->first->data() || !aCIter->first->data()->isValid())
237         anInvalidConstraints.insert(aCIter->first);
238     }
239     std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
240     for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
241       removeConstraint(*aRemoveIt);
242
243     // remove invalid features
244     myStorage->removeInvalidEntities();
245
246     // show DoF
247     computeDoF();
248   }
249 }
250
251 // ============================================================================
252 //  Function: removeTemporaryConstraints
253 //  Class:    SketchSolver_Group
254 //  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
255 //            resolving the set of constraints
256 // ============================================================================
257 void SketchSolver_Group::removeTemporaryConstraints()
258 {
259   if (!myTempConstraints.empty()) {
260     std::dynamic_pointer_cast<PlaneGCSSolver_Solver>(
261         mySketchSolver)->removeConstraint(CID_MOVEMENT);
262
263     std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
264     for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
265       (*aTmpIt)->remove();
266
267     myTempConstraints.clear();
268   }
269
270   myStorage->setNeedToResolve(false);
271 }
272
273 // ============================================================================
274 //  Function: removeConstraint
275 //  Class:    SketchSolver_Group
276 //  Purpose:  remove constraint and all unused entities
277 // ============================================================================
278 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
279 {
280   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
281   for (; aCIter != myConstraints.end(); aCIter++)
282     if (aCIter->first == theConstraint) {
283       aCIter->second->remove(); // the constraint is not fully removed
284       break;
285     }
286   if (aCIter != myConstraints.end())
287     myConstraints.erase(aCIter);
288 }
289
290 // ============================================================================
291 //  Function: setTemporary
292 //  Class:    SketchSolver_Group
293 //  Purpose:  append given constraint to the group of temporary constraints
294 // ============================================================================
295 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
296 {
297   myTempConstraints.insert(theConstraint);
298 }
299
300 // ============================================================================
301 //  Function: blockEvents
302 //  Class:    SketchSolver_Group
303 //  Purpose:  block or unblock events from features in this group
304 // ============================================================================
305 void SketchSolver_Group::blockEvents(bool isBlocked)
306 {
307   if (myIsEventsBlocked == isBlocked)
308     return;
309
310   // block/unblock events from the features in the storage
311   myStorage->blockEvents(isBlocked);
312
313   // block/unblock events from constraints
314   ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
315   for (; aCIt != myConstraints.end(); ++aCIt)
316     aCIt->second->blockEvents(isBlocked);
317
318   myIsEventsBlocked = isBlocked;
319 }