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) {
214 // Check if the group contains only constraints Fixed, update parameters by stored values
216 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
217 for (; aCIt != myConstraints.end(); ++aCIt)
218 if (aCIt->first->getKind() != SketchPlugin_ConstraintRigid::ID()) {
222 if (aCIt == myConstraints.end())
223 myStorage->refresh();
224 } else if (isGroupEmpty && isWorkplaneValid())
226 removeTemporaryConstraints();
227 myStorage->setNeedToResolve(false);
231 // ============================================================================
232 // Function: computeDoF
233 // Class: SketchSolver_Group
234 // Purpose: compute DoF of the sketch and set corresponding field
235 // ============================================================================
236 void SketchSolver_Group::computeDoF()
238 std::ostringstream aDoFMsg;
239 int aDoF = mySketchSolver->dof();
241 aDoFMsg << "Sketch is fully fixed (DoF = 0)";
243 aDoFMsg << "DoF (degrees of freedom) = " << aDoF;
244 mySketch->string(SketchPlugin_Sketch::SOLVER_DOF())->setValue(aDoFMsg.str());
246 if (aDoF > 0 && myDOF == 0)
247 sendMessage(EVENT_SKETCH_UNDER_CONSTRAINED, mySketch, aDoF);
248 else if (aDoF == 0 && myDOF > 0)
249 sendMessage(EVENT_SKETCH_FULLY_CONSTRAINED, mySketch, aDoF);
251 sendMessage(EVENT_SKETCH_OVER_CONSTRAINED, mySketch, aDoF);
256 // ============================================================================
257 // Function: repairConsistency
258 // Class: SketchSolver_Group
259 // Purpose: search removed entities and constraints
260 // ============================================================================
261 void SketchSolver_Group::repairConsistency()
263 if (!myStorage->isConsistent()) {
264 // remove invalid constraints
265 std::set<ConstraintPtr> anInvalidConstraints;
266 ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
267 for (; aCIter != myConstraints.end(); ++aCIter) {
268 if (!aCIter->first->data() || !aCIter->first->data()->isValid())
269 anInvalidConstraints.insert(aCIter->first);
271 std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
272 for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
273 removeConstraint(*aRemoveIt);
275 // remove invalid features
276 myStorage->removeInvalidEntities();
283 // ============================================================================
284 // Function: removeTemporaryConstraints
285 // Class: SketchSolver_Group
286 // Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
287 // resolving the set of constraints
288 // ============================================================================
289 void SketchSolver_Group::removeTemporaryConstraints()
291 if (!myTempConstraints.empty()) {
292 mySketchSolver->removeConstraint(CID_MOVEMENT);
294 std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
295 for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
298 myTempConstraints.clear();
301 myStorage->setNeedToResolve(false);
304 // ============================================================================
305 // Function: removeConstraint
306 // Class: SketchSolver_Group
307 // Purpose: remove constraint and all unused entities
308 // ============================================================================
309 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
311 ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
312 for (; aCIter != myConstraints.end(); aCIter++)
313 if (aCIter->first == theConstraint) {
314 aCIter->second->remove(); // the constraint is not fully removed
317 if (aCIter != myConstraints.end())
318 myConstraints.erase(aCIter);
321 // ============================================================================
322 // Function: setTemporary
323 // Class: SketchSolver_Group
324 // Purpose: append given constraint to the group of temporary constraints
325 // ============================================================================
326 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
328 myTempConstraints.insert(theConstraint);
331 // ============================================================================
332 // Function: blockEvents
333 // Class: SketchSolver_Group
334 // Purpose: block or unblock events from features in this group
335 // ============================================================================
336 void SketchSolver_Group::blockEvents(bool isBlocked)
338 if (myIsEventsBlocked == isBlocked)
341 // block/unblock events from the features in the storage
342 myStorage->blockEvents(isBlocked);
344 // block/unblock events from constraints
345 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
346 for (; aCIt != myConstraints.end(); ++aCIt)
347 aCIt->second->blockEvents(isBlocked);
349 myIsEventsBlocked = isBlocked;