]> SALOME platform Git repositories - modules/shaper.git/blob - src/SketchSolver/SketchSolver_Group.cpp
Salome HOME
SketchSolver Refactoring: Eliminate SolveSpace as a sketch solver.
[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     } else {
180       mySketchSolver->undo();
181       if (!myConstraints.empty()) {
182         // the error message should be changed before sending the message
183         getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
184           ->setValue(SketchSolver_Error::CONSTRAINTS());
185         if (myPrevResult != aResult ||
186             myPrevResult == STATUS_UNKNOWN ||
187             myPrevResult == STATUS_FAILED) {
188           // Obtain list of conflicting constraints
189           std::set<ObjectPtr> aConflicting = myStorage->getConflictingConstraints(mySketchSolver);
190
191           if (!myConflictingConstraints.empty()) {
192             std::set<ObjectPtr>::iterator anIt = aConflicting.begin();
193             for (; anIt != aConflicting.end(); ++anIt)
194               myConflictingConstraints.erase(*anIt);
195             if (!myConflictingConstraints.empty()) {
196               // some constraints does not conflict, send corresponding message
197               sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
198             }
199           }
200           myConflictingConstraints = aConflicting;
201           if (!myConflictingConstraints.empty())
202             sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints);
203           myPrevResult = aResult;
204         }
205       }
206     }
207
208     aResolved = true;
209   } else if (!isGroupEmpty) {
210     // Check if the group contains only constraints Fixed, update parameters by stored values
211     aResolved = true;
212     ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
213     for (; aCIt != myConstraints.end(); ++aCIt)
214       if (aCIt->first->getKind() != SketchPlugin_ConstraintRigid::ID()) {
215         aResolved = false;
216         break;
217       }
218     if (aCIt == myConstraints.end())
219       myStorage->refresh();
220   }
221   removeTemporaryConstraints();
222   myStorage->setNeedToResolve(false);
223   return aResolved;
224 }
225
226 // ============================================================================
227 //  Function: repairConsistency
228 //  Class:    SketchSolver_Group
229 //  Purpose:  search removed entities and constraints
230 // ============================================================================
231 void SketchSolver_Group::repairConsistency()
232 {
233   if (!myStorage->isConsistent()) {
234     // remove invalid constraints
235     std::set<ConstraintPtr> anInvalidConstraints;
236     ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
237     for (; aCIter != myConstraints.end(); ++aCIter) {
238       if (!aCIter->first->data() || !aCIter->first->data()->isValid())
239         anInvalidConstraints.insert(aCIter->first);
240     }
241     std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
242     for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
243       removeConstraint(*aRemoveIt);
244
245     // remove invalid features
246     myStorage->removeInvalidEntities();
247   }
248 }
249
250 // ============================================================================
251 //  Function: removeTemporaryConstraints
252 //  Class:    SketchSolver_Group
253 //  Purpose:  remove all transient SLVS_C_WHERE_DRAGGED constraints after
254 //            resolving the set of constraints
255 // ============================================================================
256 void SketchSolver_Group::removeTemporaryConstraints()
257 {
258   if (!myTempConstraints.empty()) {
259     std::dynamic_pointer_cast<PlaneGCSSolver_Solver>(
260         mySketchSolver)->removeConstraint(CID_MOVEMENT);
261
262     std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
263     for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
264       (*aTmpIt)->remove();
265
266     myTempConstraints.clear();
267   }
268
269   myStorage->setNeedToResolve(false);
270 }
271
272 // ============================================================================
273 //  Function: removeConstraint
274 //  Class:    SketchSolver_Group
275 //  Purpose:  remove constraint and all unused entities
276 // ============================================================================
277 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
278 {
279   ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
280   for (; aCIter != myConstraints.end(); aCIter++)
281     if (aCIter->first == theConstraint) {
282       aCIter->second->remove(); // the constraint is not fully removed
283       break;
284     }
285   if (aCIter != myConstraints.end())
286     myConstraints.erase(aCIter);
287 }
288
289 // ============================================================================
290 //  Function: setTemporary
291 //  Class:    SketchSolver_Group
292 //  Purpose:  append given constraint to the group of temporary constraints
293 // ============================================================================
294 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
295 {
296   myTempConstraints.insert(theConstraint);
297 }
298
299 // ============================================================================
300 //  Function: blockEvents
301 //  Class:    SketchSolver_Group
302 //  Purpose:  block or unblock events from features in this group
303 // ============================================================================
304 void SketchSolver_Group::blockEvents(bool isBlocked)
305 {
306   if (myIsEventsBlocked == isBlocked)
307     return;
308
309   // block/unblock events from the features in the storage
310   myStorage->blockEvents(isBlocked);
311
312   // block/unblock events from constraints
313   ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
314   for (; aCIt != myConstraints.end(); ++aCIt)
315     aCIt->second->blockEvents(isBlocked);
316
317   myIsEventsBlocked = isBlocked;
318 }