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 // show degrees of freedom
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);
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);
203 myConflictingConstraints = aConflicting;
204 if (!myConflictingConstraints.empty())
205 sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints);
206 myPrevResult = aResult;
212 } else if (!isGroupEmpty) {
213 // Check if the group contains only constraints Fixed, update parameters by stored values
215 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
216 for (; aCIt != myConstraints.end(); ++aCIt)
217 if (aCIt->first->getKind() != SketchPlugin_ConstraintRigid::ID()) {
221 if (aCIt == myConstraints.end())
222 myStorage->refresh();
223 } else if (isGroupEmpty)
225 removeTemporaryConstraints();
226 myStorage->setNeedToResolve(false);
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
237 std::ostringstream aDoFMsg;
238 int aDoF = /*isEmpty() ? myStorage->numberOfParameters() :*/ mySketchSolver->dof();
240 aDoFMsg << "Sketch is fully fixed (DoF = 0)";
242 aDoFMsg << "DoF (degrees of freedom) = " << aDoF;
243 mySketch->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aDoFMsg.str());
246 // ============================================================================
247 // Function: repairConsistency
248 // Class: SketchSolver_Group
249 // Purpose: search removed entities and constraints
250 // ============================================================================
251 void SketchSolver_Group::repairConsistency()
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);
261 std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
262 for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
263 removeConstraint(*aRemoveIt);
265 // remove invalid features
266 myStorage->removeInvalidEntities();
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()
281 if (!myTempConstraints.empty()) {
282 std::dynamic_pointer_cast<PlaneGCSSolver_Solver>(
283 mySketchSolver)->removeConstraint(CID_MOVEMENT);
285 std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
286 for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
289 myTempConstraints.clear();
292 myStorage->setNeedToResolve(false);
295 // ============================================================================
296 // Function: removeConstraint
297 // Class: SketchSolver_Group
298 // Purpose: remove constraint and all unused entities
299 // ============================================================================
300 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
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
308 if (aCIter != myConstraints.end())
309 myConstraints.erase(aCIter);
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)
319 myTempConstraints.insert(theConstraint);
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)
329 if (myIsEventsBlocked == isBlocked)
332 // block/unblock events from the features in the storage
333 myStorage->blockEvents(isBlocked);
335 // block/unblock events from constraints
336 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
337 for (; aCIt != myConstraints.end(); ++aCIt)
338 aCIt->second->blockEvents(isBlocked);
340 myIsEventsBlocked = isBlocked;