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);
37 static void sendMessage(const char* theMessageName,
38 const CompositeFeaturePtr& theSketch,
41 std::shared_ptr<ModelAPI_SolverFailedMessage> aMessage =
42 std::shared_ptr<ModelAPI_SolverFailedMessage>(
43 new ModelAPI_SolverFailedMessage(Events_Loop::eventByName(theMessageName)));
45 std::set<ObjectPtr> anObjects;
46 anObjects.insert(theSketch);
47 aMessage->setObjects(anObjects);
48 aMessage->dof(theDOF);
50 Events_Loop::loop()->send(aMessage);
55 // ========================================================
56 // ========= SketchSolver_Group ===============
57 // ========================================================
59 SketchSolver_Group::SketchSolver_Group(const CompositeFeaturePtr& theWorkplane)
60 : mySketch(theWorkplane),
61 myPrevResult(PlaneGCSSolver_Solver::STATUS_UNKNOWN),
63 myIsEventsBlocked(false)
65 mySketchSolver = SolverPtr(new PlaneGCSSolver_Solver);
66 myStorage = StoragePtr(new PlaneGCSSolver_Storage(mySketchSolver));
69 SketchSolver_Group::~SketchSolver_Group()
71 myConstraints.clear();
72 // send the message that there is no more conflicting constraints
73 if (!myConflictingConstraints.empty()) {
74 sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
75 myConflictingConstraints.clear();
79 // ============================================================================
80 // Function: changeConstraint
81 // Class: SketchSolver_Group
82 // Purpose: create/update the constraint in the group
83 // ============================================================================
84 bool SketchSolver_Group::changeConstraint(
85 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
87 bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end();
88 if (isNewConstraint) {
89 // Add constraint to the current group
90 SolverConstraintPtr aConstraint = PlaneGCSSolver_Tools::createConstraint(theConstraint);
93 aConstraint->process(myStorage, myIsEventsBlocked);
94 if (!aConstraint->error().empty()) {
95 if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
96 return false; // some attribute are not initialized yet, don't show message
97 Events_InfoMessage("SketchSolver_Group", aConstraint->error(), this).send();
99 myConstraints[theConstraint] = aConstraint;
102 myConstraints[theConstraint]->update();
106 bool SketchSolver_Group::updateFeature(FeaturePtr theFeature)
108 return myStorage->update(theFeature);
111 bool SketchSolver_Group::moveFeature(FeaturePtr theFeature)
114 // avoid moving elements of fully constrained sketch
115 myStorage->refresh();
119 // Create temporary Fixed constraint
120 SolverConstraintPtr aConstraint = PlaneGCSSolver_Tools::createMovementConstraint(theFeature);
123 aConstraint->process(myStorage, myIsEventsBlocked);
124 if (aConstraint->error().empty())
125 setTemporary(aConstraint);
127 myStorage->notify(theFeature);
132 // ============================================================================
133 // Function: resolveConstraints
134 // Class: SketchSolver_Group
135 // Purpose: solve the set of constraints for the current group
136 // ============================================================================
137 bool SketchSolver_Group::resolveConstraints()
139 bool aResolved = false;
140 bool isGroupEmpty = isEmpty() && myStorage->isEmpty();
141 if (myStorage->isNeedToResolve() &&
142 (!isGroupEmpty || !myConflictingConstraints.empty() ||
143 myPrevResult == PlaneGCSSolver_Solver::STATUS_FAILED)) {
145 PlaneGCSSolver_Solver::SolveStatus aResult = PlaneGCSSolver_Solver::STATUS_OK;
148 aResult = mySketchSolver->solve();
150 getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
151 ->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
152 if (myPrevResult == PlaneGCSSolver_Solver::STATUS_OK ||
153 myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN) {
154 // the error message should be changed before sending the message
155 sendMessage(EVENT_SOLVER_FAILED);
156 myPrevResult = PlaneGCSSolver_Solver::STATUS_FAILED;
158 mySketchSolver->undo();
161 // solution succeeded, store results into correspondent attributes
162 if (aResult == PlaneGCSSolver_Solver::STATUS_OK ||
163 aResult == PlaneGCSSolver_Solver::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 != PlaneGCSSolver_Solver::STATUS_OK ||
172 myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN) {
173 getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
174 std::set<ObjectPtr> aConflicting = myConflictingConstraints;
175 myConflictingConstraints.clear();
176 myPrevResult = PlaneGCSSolver_Solver::STATUS_OK;
177 // the error message should be changed before sending the message
178 sendMessage(EVENT_SOLVER_REPAIRED, aConflicting);
181 // show degrees of freedom
184 mySketchSolver->undo();
185 if (!myConstraints.empty()) {
186 // the error message should be changed before sending the message
187 getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())
188 ->setValue(SketchSolver_Error::CONSTRAINTS());
189 if (myPrevResult != aResult ||
190 myPrevResult == PlaneGCSSolver_Solver::STATUS_UNKNOWN ||
191 myPrevResult == PlaneGCSSolver_Solver::STATUS_FAILED) {
192 // Obtain list of conflicting constraints
193 std::set<ObjectPtr> aConflicting = myStorage->getConflictingConstraints(mySketchSolver);
195 if (!myConflictingConstraints.empty()) {
196 std::set<ObjectPtr>::iterator anIt = aConflicting.begin();
197 for (; anIt != aConflicting.end(); ++anIt)
198 myConflictingConstraints.erase(*anIt);
199 if (!myConflictingConstraints.empty()) {
200 // some constraints does not conflict, send corresponding message
201 sendMessage(EVENT_SOLVER_REPAIRED, myConflictingConstraints);
204 myConflictingConstraints = aConflicting;
205 if (!myConflictingConstraints.empty())
206 sendMessage(EVENT_SOLVER_FAILED, myConflictingConstraints);
207 myPrevResult = aResult;
213 } else if (isGroupEmpty && isWorkplaneValid())
215 removeTemporaryConstraints();
216 myStorage->setNeedToResolve(false);
220 // ============================================================================
221 // Function: computeDoF
222 // Class: SketchSolver_Group
223 // Purpose: compute DoF of the sketch and set corresponding field
224 // ============================================================================
225 void SketchSolver_Group::computeDoF()
227 std::ostringstream aDoFMsg;
228 int aDoF = mySketchSolver->dof();
230 aDoFMsg << "Sketch is fully fixed (DoF = 0)";
232 aDoFMsg << "DoF (degrees of freedom) = " << aDoF;
233 mySketch->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aDoFMsg.str());
235 if (aDoF > 0 && myDOF == 0)
236 sendMessage(EVENT_SKETCH_UNDER_CONSTRAINED, mySketch, aDoF);
237 else if (aDoF == 0 && myDOF > 0)
238 sendMessage(EVENT_SKETCH_FULLY_CONSTRAINED, mySketch, aDoF);
240 sendMessage(EVENT_SKETCH_OVER_CONSTRAINED, mySketch, aDoF);
245 // ============================================================================
246 // Function: repairConsistency
247 // Class: SketchSolver_Group
248 // Purpose: search removed entities and constraints
249 // ============================================================================
250 void SketchSolver_Group::repairConsistency()
252 if (!myStorage->isConsistent()) {
253 // remove invalid constraints
254 std::set<ConstraintPtr> anInvalidConstraints;
255 ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
256 for (; aCIter != myConstraints.end(); ++aCIter) {
257 if (!aCIter->first->data() || !aCIter->first->data()->isValid())
258 anInvalidConstraints.insert(aCIter->first);
260 std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
261 for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
262 removeConstraint(*aRemoveIt);
264 // remove invalid features
265 myStorage->removeInvalidEntities();
272 // ============================================================================
273 // Function: removeTemporaryConstraints
274 // Class: SketchSolver_Group
275 // Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
276 // resolving the set of constraints
277 // ============================================================================
278 void SketchSolver_Group::removeTemporaryConstraints()
280 if (!myTempConstraints.empty()) {
281 mySketchSolver->removeConstraint(CID_MOVEMENT);
283 std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
284 for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
287 myTempConstraints.clear();
290 myStorage->setNeedToResolve(false);
293 // ============================================================================
294 // Function: removeConstraint
295 // Class: SketchSolver_Group
296 // Purpose: remove constraint and all unused entities
297 // ============================================================================
298 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
300 ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
301 for (; aCIter != myConstraints.end(); aCIter++)
302 if (aCIter->first == theConstraint) {
303 aCIter->second->remove(); // the constraint is not fully removed
306 if (aCIter != myConstraints.end())
307 myConstraints.erase(aCIter);
310 // ============================================================================
311 // Function: setTemporary
312 // Class: SketchSolver_Group
313 // Purpose: append given constraint to the group of temporary constraints
314 // ============================================================================
315 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
317 myTempConstraints.insert(theConstraint);
320 // ============================================================================
321 // Function: blockEvents
322 // Class: SketchSolver_Group
323 // Purpose: block or unblock events from features in this group
324 // ============================================================================
325 void SketchSolver_Group::blockEvents(bool isBlocked)
327 if (myIsEventsBlocked == isBlocked)
330 // block/unblock events from the features in the storage
331 myStorage->blockEvents(isBlocked);
333 // block/unblock events from constraints
334 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
335 for (; aCIt != myConstraints.end(); ++aCIt)
336 aCIt->second->blockEvents(isBlocked);
338 myIsEventsBlocked = isBlocked;