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>
13 #include <Events_InfoMessage.h>
14 #include <ModelAPI_AttributeString.h>
15 #include <ModelAPI_Events.h>
16 #include <SketchPlugin_ConstraintRigid.h>
19 static void sendMessage(const char* theMessageName)
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);
26 static void sendMessage(const char* theMessageName, const std::set<ObjectPtr>& theConflicting)
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);
37 // ========================================================
38 // ========= SketchSolver_Group ===============
39 // ========================================================
41 SketchSolver_Group::SketchSolver_Group(const CompositeFeaturePtr& theWorkplane)
42 : mySketch(theWorkplane),
43 myPrevResult(STATUS_UNKNOWN),
44 myIsEventsBlocked(false)
46 BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
47 mySketchSolver = aBuilder->createSolver();
48 myStorage = aBuilder->createStorage(mySketchSolver);
51 SketchSolver_Group::~SketchSolver_Group()
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();
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)
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);
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();
82 myConstraints[theConstraint] = aConstraint;
85 myConstraints[theConstraint]->update();
89 bool SketchSolver_Group::updateFeature(FeaturePtr theFeature)
91 return myStorage->update(theFeature);
94 bool SketchSolver_Group::moveFeature(FeaturePtr theFeature)
96 BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
98 // Create temporary Fixed constraint
99 SolverConstraintPtr aConstraint = aBuilder->createMovementConstraint(theFeature);
102 aConstraint->process(myStorage, myIsEventsBlocked);
103 if (aConstraint->error().empty())
104 setTemporary(aConstraint);
106 myStorage->notify(theFeature);
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()
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();
125 //// mySketchSolver->calculateFailedConstraints(false);
126 myStorage->initializeSolver();
127 //// mySketchSolver->prepare();
129 SketchSolver_SolveStatus aResult = STATUS_OK;
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;
136 aResult = mySketchSolver->solve();
137 if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET || isLastChance)
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();
145 removeTemporaryConstraints();
146 mySketchSolver->calculateFailedConstraints(true); // something failed => need to find it
147 myStorage->initializeSolver();
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;
159 mySketchSolver->undo();
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();
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);
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);
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);
200 myConflictingConstraints = aConflicting;
201 if (!myConflictingConstraints.empty())
202 sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints);
203 myPrevResult = aResult;
209 } else if (!isGroupEmpty) {
210 // Check if the group contains only constraints Fixed, update parameters by stored values
212 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
213 for (; aCIt != myConstraints.end(); ++aCIt)
214 if (aCIt->first->getKind() != SketchPlugin_ConstraintRigid::ID()) {
218 if (aCIt == myConstraints.end())
219 myStorage->refresh();
221 removeTemporaryConstraints();
222 myStorage->setNeedToResolve(false);
226 // ============================================================================
227 // Function: repairConsistency
228 // Class: SketchSolver_Group
229 // Purpose: search removed entities and constraints
230 // ============================================================================
231 void SketchSolver_Group::repairConsistency()
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);
241 std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
242 for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
243 removeConstraint(*aRemoveIt);
245 // remove invalid features
246 myStorage->removeInvalidEntities();
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()
258 if (!myTempConstraints.empty()) {
259 std::dynamic_pointer_cast<PlaneGCSSolver_Solver>(
260 mySketchSolver)->removeConstraint(CID_MOVEMENT);
262 std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
263 for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
266 myTempConstraints.clear();
269 myStorage->setNeedToResolve(false);
272 // ============================================================================
273 // Function: removeConstraint
274 // Class: SketchSolver_Group
275 // Purpose: remove constraint and all unused entities
276 // ============================================================================
277 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
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
285 if (aCIter != myConstraints.end())
286 myConstraints.erase(aCIter);
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)
296 myTempConstraints.insert(theConstraint);
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)
306 if (myIsEventsBlocked == isBlocked)
309 // block/unblock events from the features in the storage
310 myStorage->blockEvents(isBlocked);
312 // block/unblock events from constraints
313 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
314 for (; aCIt != myConstraints.end(); ++aCIt)
315 aCIt->second->blockEvents(isBlocked);
317 myIsEventsBlocked = isBlocked;