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>
12 #include <PlaneGCSSolver_Storage.h>
13 #include <PlaneGCSSolver_Tools.h>
15 #include <Events_InfoMessage.h>
16 #include <ModelAPI_AttributeString.h>
17 #include <ModelAPI_Events.h>
18 #include <SketchPlugin_ConstraintRigid.h>
21 static void sendMessage(const char* theMessageName)
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);
28 static void sendMessage(const char* theMessageName, const std::set<ObjectPtr>& theConflicting)
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);
39 // ========================================================
40 // ========= SketchSolver_Group ===============
41 // ========================================================
43 SketchSolver_Group::SketchSolver_Group(const CompositeFeaturePtr& theWorkplane)
44 : mySketch(theWorkplane),
45 myPrevResult(PlaneGCSSolver_Solver::STATUS_UNKNOWN),
46 myIsEventsBlocked(false)
48 mySketchSolver = SolverPtr(new PlaneGCSSolver_Solver);
49 myStorage = StoragePtr(new PlaneGCSSolver_Storage(mySketchSolver));
52 SketchSolver_Group::~SketchSolver_Group()
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();
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)
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);
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 // Create temporary Fixed constraint
97 SolverConstraintPtr aConstraint = PlaneGCSSolver_Tools::createMovementConstraint(theFeature);
100 aConstraint->process(myStorage, myIsEventsBlocked);
101 if (aConstraint->error().empty())
102 setTemporary(aConstraint);
104 myStorage->notify(theFeature);
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()
116 bool aResolved = false;
117 bool isGroupEmpty = isEmpty() && myStorage->isEmpty();
118 if (myStorage->isNeedToResolve() &&
119 (!isGroupEmpty || !myConflictingConstraints.empty() ||
120 myPrevResult == PlaneGCSSolver_Solver::STATUS_FAILED)) {
122 PlaneGCSSolver_Solver::SolveStatus aResult = PlaneGCSSolver_Solver::STATUS_OK;
125 aResult = mySketchSolver->solve();
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;
135 mySketchSolver->undo();
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();
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);
158 // show degrees of freedom
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);
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);
181 myConflictingConstraints = aConflicting;
182 if (!myConflictingConstraints.empty())
183 sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints);
184 myPrevResult = aResult;
190 } else if (!isGroupEmpty) {
191 // Check if the group contains only constraints Fixed, update parameters by stored values
193 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
194 for (; aCIt != myConstraints.end(); ++aCIt)
195 if (aCIt->first->getKind() != SketchPlugin_ConstraintRigid::ID()) {
199 if (aCIt == myConstraints.end())
200 myStorage->refresh();
201 } else if (isGroupEmpty && isWorkplaneValid())
203 removeTemporaryConstraints();
204 myStorage->setNeedToResolve(false);
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
215 std::ostringstream aDoFMsg;
216 int aDoF = /*isEmpty() ? myStorage->numberOfParameters() :*/ mySketchSolver->dof();
218 aDoFMsg << "Sketch is fully fixed (DoF = 0)";
220 aDoFMsg << "DoF (degrees of freedom) = " << aDoF;
221 mySketch->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aDoFMsg.str());
224 // ============================================================================
225 // Function: repairConsistency
226 // Class: SketchSolver_Group
227 // Purpose: search removed entities and constraints
228 // ============================================================================
229 void SketchSolver_Group::repairConsistency()
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);
239 std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
240 for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
241 removeConstraint(*aRemoveIt);
243 // remove invalid features
244 myStorage->removeInvalidEntities();
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()
259 if (!myTempConstraints.empty()) {
260 std::dynamic_pointer_cast<PlaneGCSSolver_Solver>(
261 mySketchSolver)->removeConstraint(CID_MOVEMENT);
263 std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
264 for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
267 myTempConstraints.clear();
270 myStorage->setNeedToResolve(false);
273 // ============================================================================
274 // Function: removeConstraint
275 // Class: SketchSolver_Group
276 // Purpose: remove constraint and all unused entities
277 // ============================================================================
278 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
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
286 if (aCIter != myConstraints.end())
287 myConstraints.erase(aCIter);
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)
297 myTempConstraints.insert(theConstraint);
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)
307 if (myIsEventsBlocked == isBlocked)
310 // block/unblock events from the features in the storage
311 myStorage->blockEvents(isBlocked);
313 // block/unblock events from constraints
314 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
315 for (; aCIt != myConstraints.end(); ++aCIt)
316 aCIt->second->blockEvents(isBlocked);
318 myIsEventsBlocked = isBlocked;