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"
9 #include <SketchSolver_Constraint.h>
10 #include <SketchSolver_ConstraintCoincidence.h>
11 #include <SketchSolver_ConstraintMulti.h>
12 #include <SketchSolver_Error.h>
13 ////#include <SketchSolver_Builder.h>
14 #include <SketchSolver_Manager.h>
16 #include <Events_Error.h>
17 #include <Events_Loop.h>
18 ////#include <GeomAPI_XY.h>
19 ////#include <GeomAPI_Dir2d.h>
20 ////#include <GeomAPI_Pnt2d.h>
21 ////#include <GeomDataAPI_Dir.h>
22 ////#include <GeomDataAPI_Point.h>
23 ////#include <GeomDataAPI_Point2D.h>
24 ////#include <ModelAPI_AttributeDouble.h>
25 #include <ModelAPI_AttributeString.h>
26 ////#include <ModelAPI_Document.h>
27 #include <ModelAPI_Events.h>
28 ////#include <ModelAPI_ResultConstruction.h>
29 #include <ModelAPI_Session.h>
30 #include <ModelAPI_Validator.h>
32 ////#include <SketchPlugin_Constraint.h>
33 #include <SketchPlugin_ConstraintAngle.h>
34 #include <SketchPlugin_ConstraintCoincidence.h>
35 #include <SketchPlugin_ConstraintDistance.h>
36 #include <SketchPlugin_ConstraintEqual.h>
37 #include <SketchPlugin_ConstraintHorizontal.h>
38 #include <SketchPlugin_ConstraintLength.h>
39 #include <SketchPlugin_ConstraintFillet.h>
40 #include <SketchPlugin_ConstraintMirror.h>
41 #include <SketchPlugin_ConstraintParallel.h>
42 #include <SketchPlugin_ConstraintPerpendicular.h>
43 #include <SketchPlugin_ConstraintRadius.h>
44 #include <SketchPlugin_ConstraintRigid.h>
45 #include <SketchPlugin_ConstraintTangent.h>
46 #include <SketchPlugin_ConstraintVertical.h>
47 ////#include <SketchPlugin_Feature.h>
48 #include <SketchPlugin_MultiRotation.h>
49 #include <SketchPlugin_MultiTranslation.h>
50 ////#include <SketchPlugin_Sketch.h>
52 ////#include <SketchPlugin_Arc.h>
53 ////#include <SketchPlugin_Circle.h>
54 ////#include <SketchPlugin_Line.h>
55 ////#include <SketchPlugin_Point.h>
56 ////#include <SketchPlugin_Sketch.h>
62 /// \brief This class is used to give unique index to the groups
66 /// \brief Return vacant index
67 static GroupID NEW_GROUP() { return ++myGroupIndex; }
68 /// \brief Removes the index
69 static void REMOVE_GROUP(const GroupID& theIndex) {
70 if (myGroupIndex == theIndex)
77 static GroupID myGroupIndex; ///< index of the group
80 GroupID GroupIndexer::myGroupIndex = GID_OUTOFGROUP;
83 static void sendMessage(const char* theMessageName)
85 std::shared_ptr<Events_Message> aMessage = std::shared_ptr<Events_Message>(
86 new Events_Message(Events_Loop::eventByName(theMessageName)));
87 Events_Loop::loop()->send(aMessage);
92 // ========================================================
93 // ========= SketchSolver_Group ===============
94 // ========================================================
96 SketchSolver_Group::SketchSolver_Group(
97 std::shared_ptr<ModelAPI_CompositeFeature> theWorkplane)
98 : myID(GroupIndexer::NEW_GROUP()),
101 // Initialize workplane
102 myWorkplaneID = EID_UNKNOWN;
103 addWorkplane(theWorkplane);
106 SketchSolver_Group::~SketchSolver_Group()
108 myConstraints.clear();
109 GroupIndexer::REMOVE_GROUP(myID);
112 // ============================================================================
113 // Function: isBaseWorkplane
114 // Class: SketchSolver_Group
115 // Purpose: verify the group is based on the given workplane
116 // ============================================================================
117 bool SketchSolver_Group::isBaseWorkplane(CompositeFeaturePtr theWorkplane) const
119 return theWorkplane == mySketch;
122 // ============================================================================
123 // Function: isInteract
124 // Class: SketchSolver_Group
125 // Purpose: verify are there any entities in the group used by given constraint
126 // ============================================================================
127 bool SketchSolver_Group::isInteract(FeaturePtr theFeature) const
129 // Empty group interacts with everything
132 // Check interaction with the storage
133 return myStorage->isInteract(theFeature);
136 // ============================================================================
137 // Function: changeConstraint
138 // Class: SketchSolver_Group
139 // Purpose: create/update the constraint in the group
140 // ============================================================================
141 bool SketchSolver_Group::changeConstraint(
142 std::shared_ptr<SketchPlugin_Constraint> theConstraint)
144 // There is no workplane yet, something wrong
145 if (myWorkplaneID == EID_UNKNOWN)
148 if (!theConstraint || !theConstraint->data())
151 if (!checkFeatureValidity(theConstraint))
154 BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
156 bool isNewConstraint = myConstraints.find(theConstraint) == myConstraints.end();
157 if (isNewConstraint) {
158 // Add constraint to the current group
159 SolverConstraintPtr aConstraint = aBuilder->createConstraint(theConstraint);
162 aConstraint->process(myStorage, getId(), getWorkplaneId());
163 if (!aConstraint->error().empty()) {
164 if (aConstraint->error() == SketchSolver_Error::NOT_INITIALIZED())
165 return false; // some attribute are not initialized yet, don't show message
166 Events_Error::send(aConstraint->error(), this);
169 //// // Additional verification of coincidence of several points
170 //// if (aConstraint->getType() == CONSTRAINT_PT_PT_COINCIDENT) {
171 //// bool hasMultiCoincidence = false;
172 //// std::shared_ptr<SketchSolver_ConstraintCoincidence> aCoincidence =
173 //// std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aConstraint);
175 //// ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
176 //// for (; aCIter != myConstraints.end(); ++aCIter) {
177 //// if (aCIter->second->getType() != CONSTRAINT_PT_PT_COINCIDENT)
180 //// std::shared_ptr<SketchSolver_ConstraintCoincidence> aCurCoinc =
181 //// std::dynamic_pointer_cast<SketchSolver_ConstraintCoincidence>(aCIter->second);
182 //// if (aCoincidence != aCurCoinc && aCurCoinc->isCoincide(aCoincidence)) {
183 //// aCoincidence->attach(aCurCoinc);
184 //////// // update other coincidences
185 //////// ConstraintConstraintMap::iterator anIt = aCIter;
186 //////// for (++anIt; anIt != myConstraints.end(); ++anIt)
187 //////// if (anIt->second == aCIter->second)
188 //////// anIt->second = aCoincidence;
189 //// aCIter->second = aCoincidence;
190 //// hasMultiCoincidence = true;
194 //// if (hasMultiCoincidence)
195 //// notifyMultiConstraints();
197 myConstraints[theConstraint] = aConstraint;
200 myConstraints[theConstraint]->update();
202 //// // Fix base features for fillet
203 //// if (isNewConstraint && theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID()) {
204 //// std::list<AttributePtr> anAttrList =
205 //// theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
206 //// std::list<AttributePtr>::iterator anAttrIter = anAttrList.begin();
207 //// for (; anAttrIter != anAttrList.end(); anAttrIter++) {
208 //// AttributeRefAttrPtr aRefAttr =
209 //// std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
210 //// if (!aRefAttr || !aRefAttr->isObject())
212 //// FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr->object());
213 //// SolverConstraintPtr aConstraint = aBuilder->createRigidConstraint(aFeature);
214 //// if (!aConstraint)
216 //// aConstraint->setGroup(this);
217 //// aConstraint->setStorage(myStorage);
218 //// setTemporary(aConstraint);
223 if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID()) {
224 AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
225 theConstraint->attribute(SketchPlugin_ConstraintMirror::ENTITY_A()));
226 if (aRefAttr && aRefAttr->isObject()) {
227 std::shared_ptr<SketchPlugin_Feature> aFeature =
228 std::dynamic_pointer_cast<SketchPlugin_Feature>(
229 ModelAPI_Feature::feature(aRefAttr->object()));
231 SolverConstraintPtr aConstraint = aBuilder->createFixedConstraint(aFeature);
233 aConstraint->process(myStorage, getId(), getWorkplaneId());
234 setTemporary(aConstraint);
240 //// // Check the attributes of constraint are given by parametric expression
241 //// std::list<AttributePtr> anAttributes =
242 //// theConstraint->data()->attributes(ModelAPI_AttributeRefAttr::typeId());
243 //// std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
244 //// for (; anAttrIt != anAttributes.end(); ++anAttrIt) {
245 //// AttributeRefAttrPtr aRefAttr =
246 //// std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIt);
250 //// std::shared_ptr<GeomDataAPI_Point2D> aPoint;
251 //// if (aRefAttr->isObject()) {
252 //// FeaturePtr aFeat = ModelAPI_Feature::feature(aRefAttr->object());
253 //// if (aFeat->getKind() != SketchPlugin_Point::ID())
255 //// aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
256 //// aFeat->attribute(SketchPlugin_Point::COORD_ID()));
258 //// aPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aRefAttr->attr());
260 //// if (!aPoint || (aPoint->textX().empty() && aPoint->textY().empty()))
263 //// std::map<AttributePtr, SolverConstraintPtr>::iterator aFound =
264 //// myParametricConstraints.find(aPoint);
265 //// if (aFound == myParametricConstraints.end()) {
266 //// SolverConstraintPtr aConstraint = aBuilder->createParametricConstraint(aPoint);
267 //// if (!aConstraint)
269 //// aConstraint->setGroup(this);
270 //// aConstraint->setStorage(myStorage);
271 //// myParametricConstraints[aPoint] = aConstraint;
273 //// aFound->second->update();
280 void SketchSolver_Group::updateConstraints()
282 std::set<SolverConstraintPtr> aPostponed; // postponed constraints Multi-Rotation and Multi-Translation
284 ConstraintConstraintMap::iterator anIt = myConstraints.begin();
285 for (; anIt != myConstraints.end(); ++anIt) {
286 if (myChangedConstraints.find(anIt->first) == myChangedConstraints.end())
288 if (anIt->first->getKind() == SketchPlugin_MultiRotation::ID() ||
289 anIt->first->getKind() == SketchPlugin_MultiTranslation::ID())
290 aPostponed.insert(anIt->second);
292 anIt->second->update();
295 // Update postponed constraints
296 std::set<SolverConstraintPtr>::iterator aSCIter = aPostponed.begin();
297 for (; aSCIter != aPostponed.end(); ++aSCIter)
298 (*aSCIter)->update();
300 myChangedConstraints.clear();
303 bool SketchSolver_Group::updateFeature(FeaturePtr theFeature)
305 if (!checkFeatureValidity(theFeature))
308 bool isUpdated = myStorage->update(theFeature);
310 //// // Search attributes of the feature in the set of parametric constraints and update them
311 //// std::list<AttributePtr> anAttrList =
312 //// theFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
313 //// std::list<AttributePtr>::iterator anAttrIt = anAttrList.begin();
314 //// for (; anAttrIt != anAttrList.end(); ++anAttrIt) {
315 //// std::map<AttributePtr, SolverConstraintPtr>::iterator aFound =
316 //// myParametricConstraints.find(*anAttrIt);
317 //// if (aFound != myParametricConstraints.end())
318 //// aFound->second->update();
320 //// std::shared_ptr<GeomDataAPI_Point2D> aPoint =
321 //// std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anAttrIt);
322 //// if (aPoint && (!aPoint->textX().empty() || !aPoint->textY().empty())) {
323 //// // Create new parametric constraint
324 //// SolverConstraintPtr aConstraint =
325 //// SketchSolver_Builder::getInstance()->createParametricConstraint(*anAttrIt);
326 //// if (!aConstraint)
328 //// aConstraint->setGroup(this);
329 //// aConstraint->setStorage(myStorage);
330 //// myParametricConstraints[*anAttrIt] = aConstraint;
337 void SketchSolver_Group::moveFeature(FeaturePtr theFeature)
339 BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
341 // Firstly, revert changes in the fixed entities
342 myStorage->refresh(true);
344 // Secondly, search attributes of the feature in the list of the Multi constraints and update them
345 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
346 for (; aCIt != myConstraints.end(); ++aCIt) {
347 if ((aCIt->second->getType() == CONSTRAINT_MULTI_ROTATION ||
348 aCIt->second->getType() == CONSTRAINT_MULTI_TRANSLATION)
349 && aCIt->second->isUsed(theFeature))
350 std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIt->second)->update(true);
353 // Then, create temporary rigid constraint
354 SolverConstraintPtr aConstraint = aBuilder->createMovementConstraint(theFeature);
357 aConstraint->process(myStorage, getId(), getWorkplaneId());
358 if (aConstraint->error().empty())
359 setTemporary(aConstraint);
362 // ============================================================================
363 // Function: addWorkplane
364 // Class: SketchSolver_Group
365 // Purpose: create workplane for the group
366 // ============================================================================
367 bool SketchSolver_Group::addWorkplane(CompositeFeaturePtr theSketch)
369 if (myWorkplaneID != EID_UNKNOWN || theSketch->getKind() != SketchPlugin_Sketch::ID())
370 return false; // the workplane already exists or the function parameter is not Sketch
372 mySketch = theSketch;
373 if (!updateWorkplane()) {
374 mySketch = CompositeFeaturePtr();
380 // ============================================================================
381 // Function: updateWorkplane
382 // Class: SketchSolver_Group
383 // Purpose: update parameters of workplane
384 // ============================================================================
385 bool SketchSolver_Group::updateWorkplane()
387 BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder();
388 if (!myStorage) // Create storage if not exists
389 myStorage = aBuilder->createStorage(getId());
391 // sketch should be unchanged, set it out of current group
392 bool isUpdated = myStorage->update(FeaturePtr(mySketch), GID_OUTOFGROUP);
394 EntityWrapperPtr anEntity = myStorage->entity(FeaturePtr(mySketch));
395 myWorkplaneID = anEntity->id();
400 // ============================================================================
401 // Function: resolveConstraints
402 // Class: SketchSolver_Group
403 // Purpose: solve the set of constraints for the current group
404 // ============================================================================
405 bool SketchSolver_Group::resolveConstraints()
407 if (!myChangedConstraints.empty())
410 bool aResolved = false;
411 bool isGroupEmpty = isEmpty();
412 if (myStorage->isNeedToResolve() && !isGroupEmpty) {
414 mySketchSolver = SketchSolver_Manager::instance()->builder()->createSolver();
416 mySketchSolver->setGroup(myID);
417 mySketchSolver->calculateFailedConstraints(false);
418 myStorage->initializeSolver(mySketchSolver);
420 SketchSolver_SolveStatus aResult = STATUS_OK;
422 if (myStorage->hasDuplicatedConstraint())
423 aResult = STATUS_INCONSISTENT;
425 // To avoid overconstraint situation, we will remove temporary constraints one-by-one
426 // and try to find the case without overconstraint
427 bool isLastChance = false;
428 size_t aNbTemp = myStorage->nbTemporary();
430 aResult = mySketchSolver->solve();
431 if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET || isLastChance)
434 // try to update parameters and resolve once again
435 ConstraintConstraintMap::iterator aConstrIt = myConstraints.begin();
436 for (; aConstrIt != myConstraints.end(); ++aConstrIt)
437 aConstrIt->second->update();
440 aNbTemp = myStorage->removeTemporary();
441 mySketchSolver->calculateFailedConstraints(true); // something failed => need to find it
442 myStorage->initializeSolver(mySketchSolver);
446 // Events_Error::send(SketchSolver_Error::SOLVESPACE_CRASH(), this);
447 getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::SOLVESPACE_CRASH());
449 // the error message should be changed before sending the message
450 sendMessage(EVENT_SOLVER_FAILED);
451 myPrevSolved = false;
455 if (aResult == STATUS_OK || aResult == STATUS_EMPTYSET) { // solution succeeded, store results into correspondent attributes
456 myStorage->refresh();
457 //// myFeatureStorage->blockEvents(true);
458 //// // First refresh parametric constraints to satisfy parameters
459 //// std::map<AttributePtr, SolverConstraintPtr>::iterator aParIter = myParametricConstraints.begin();
460 //// for (; aParIter != myParametricConstraints.end(); ++aParIter)
461 //// aParIter->second->refresh();
462 //// // Update all other constraints
463 //// ConstraintConstraintMap::iterator aConstrIter = myConstraints.begin();
464 //// for (; aConstrIter != myConstraints.end(); ++aConstrIter)
465 //// aConstrIter->second->refresh();
466 //// myFeatureStorage->blockEvents(false);
468 getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue("");
469 // the error message should be changed before sending the message
470 sendMessage(EVENT_SOLVER_REPAIRED);
473 } else if (!myConstraints.empty()) {
474 // Events_Error::send(SketchSolver_Error::CONSTRAINTS(), this);
475 getWorkplane()->string(SketchPlugin_Sketch::SOLVER_ERROR())->setValue(SketchSolver_Error::CONSTRAINTS());
477 // the error message should be changed before sending the message
478 sendMessage(EVENT_SOLVER_FAILED);
479 myPrevSolved = false;
484 } else if (!isGroupEmpty) {
485 //// myFeatureStorage->blockEvents(true);
486 // Check there are constraints Fixed. If they exist, update parameters by stored values
487 ConstraintConstraintMap::iterator aCIt = myConstraints.begin();
488 for (; aCIt != myConstraints.end(); ++aCIt)
489 if (aCIt->first->getKind() == SketchPlugin_ConstraintRigid::ID()) {
490 //// aCIt->second->refresh();
494 //// myFeatureStorage->blockEvents(false);
495 if (aCIt != myConstraints.end())
496 myStorage->refresh();
498 removeTemporaryConstraints();
499 myStorage->setNeedToResolve(false);
503 // ============================================================================
504 // Function: mergeGroups
505 // Class: SketchSolver_Group
506 // Purpose: append specified group to the current group
507 // ============================================================================
508 void SketchSolver_Group::mergeGroups(const SketchSolver_Group& theGroup)
510 // If specified group is empty, no need to merge
511 if (theGroup.isEmpty())
514 std::set<ObjectPtr> aConstraints;
515 ConstraintConstraintMap::const_iterator aConstrIter = theGroup.myConstraints.begin();
516 for (; aConstrIter != theGroup.myConstraints.end(); aConstrIter++)
517 aConstraints.insert(aConstrIter->first);
519 std::list<FeaturePtr> aSortedConstraints = selectApplicableFeatures(aConstraints);
520 std::list<FeaturePtr>::iterator aSCIter = aSortedConstraints.begin();
521 for (; aSCIter != aSortedConstraints.end(); ++aSCIter) {
522 ConstraintPtr aConstr = std::dynamic_pointer_cast<SketchPlugin_Constraint>(*aSCIter);
525 changeConstraint(aConstr);
529 // ============================================================================
530 // Function: splitGroup
531 // Class: SketchSolver_Group
532 // Purpose: divide the group into several subgroups
533 // ============================================================================
534 void SketchSolver_Group::splitGroup(std::list<SketchSolver_Group*>& theCuts)
536 // New storage will be used in trimmed way to store the list of constraint interacted together.
537 StoragePtr aNewStorage = SketchSolver_Manager::instance()->builder()->createStorage(getId());
538 std::list<ConstraintWrapperPtr> aDummyVec; // empty vector to avoid creation of solver's constraints
540 // Obtain constraints, which should be separated
541 std::list<ConstraintPtr> anUnusedConstraints;
542 ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
543 for ( ; aCIter != myConstraints.end(); aCIter++) {
544 if (aNewStorage->isInteract(FeaturePtr(aCIter->first)))
545 aNewStorage->addConstraint(aCIter->first, aDummyVec);
547 anUnusedConstraints.push_back(aCIter->first);
550 // Check the unused constraints once again, because they may become interacted with new storage since adding constraints
551 std::list<ConstraintPtr>::iterator aUnuseIt = anUnusedConstraints.begin();
552 while (aUnuseIt != anUnusedConstraints.end()) {
553 if (aNewStorage->isInteract(FeaturePtr(*aUnuseIt))) {
554 aNewStorage->addConstraint(*aUnuseIt, aDummyVec);
555 anUnusedConstraints.erase(aUnuseIt);
556 aUnuseIt = anUnusedConstraints.begin();
562 std::list<SketchSolver_Group*>::iterator aCutsIter;
563 aUnuseIt = anUnusedConstraints.begin();
564 for ( ; aUnuseIt != anUnusedConstraints.end(); ++aUnuseIt) {
565 // Remove unused constraints
566 removeConstraint(*aUnuseIt);
567 // Try to append constraint to already existent group
568 for (aCutsIter = theCuts.begin(); aCutsIter != theCuts.end(); ++aCutsIter)
569 if ((*aCutsIter)->isInteract(*aUnuseIt)) {
570 (*aCutsIter)->changeConstraint(*aUnuseIt);
573 if (aCutsIter == theCuts.end()) {
575 SketchSolver_Group* aGroup = new SketchSolver_Group(mySketch);
576 aGroup->changeConstraint(*aUnuseIt);
577 theCuts.push_back(aGroup);
579 // Find other groups interacting with constraint
580 std::list<SketchSolver_Group*>::iterator aBaseGroupIt = aCutsIter;
581 for (++aCutsIter; aCutsIter != theCuts.end(); ++aCutsIter)
582 if ((*aCutsIter)->isInteract(*aUnuseIt)) {
583 (*aBaseGroupIt)->mergeGroups(**aCutsIter);
584 std::list<SketchSolver_Group*>::iterator aRemoveIt = aCutsIter--;
585 theCuts.erase(aRemoveIt);
591 // ============================================================================
592 // Function: isConsistent
593 // Class: SketchSolver_Group
594 // Purpose: search removed entities and constraints
595 // ============================================================================
596 bool SketchSolver_Group::isConsistent()
598 if (isEmpty()) // no one constraint is initialized yet
601 // Check the features and constraint is the storage are valid
602 bool aResult = myStorage->isConsistent();
604 // additional check of consistency of the Fixed constraint,
605 // because they are not added to the storage
606 ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
607 for (; aCIter != myConstraints.end(); ++aCIter)
608 if (aCIter->first->getKind() == SketchPlugin_ConstraintRigid::ID() &&
609 (!aCIter->first->data() || !aCIter->first->data()->isValid())) {
615 // remove invalid constraints
616 std::set<ConstraintPtr> anInvalidConstraints;
617 ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
618 for (; aCIter != myConstraints.end(); ++aCIter) {
619 if (!aCIter->first->data() || !aCIter->first->data()->isValid())
620 anInvalidConstraints.insert(aCIter->first);
622 std::set<ConstraintPtr>::const_iterator aRemoveIt = anInvalidConstraints.begin();
623 for (; aRemoveIt != anInvalidConstraints.end(); ++aRemoveIt)
624 removeConstraint(*aRemoveIt);
625 // remove invalid features
626 myStorage->removeInvalidEntities();
631 // ============================================================================
632 // Function: removeTemporaryConstraints
633 // Class: SketchSolver_Group
634 // Purpose: remove all transient SLVS_C_WHERE_DRAGGED constraints after
635 // resolving the set of constraints
636 // ============================================================================
637 void SketchSolver_Group::removeTemporaryConstraints()
639 std::set<SolverConstraintPtr>::iterator aTmpIt = myTempConstraints.begin();
640 for (; aTmpIt != myTempConstraints.end(); ++aTmpIt)
643 size_t aNbTemp = myStorage->nbTemporary();
645 myStorage->removeTemporary(aNbTemp);
646 //// // Clean lists of removed entities in the storage
647 //// std::set<Slvs_hParam> aRemPar;
648 //// std::set<Slvs_hEntity> aRemEnt;
649 //// std::set<Slvs_hConstraint> aRemCon;
650 //// myStorage->getRemoved(aRemPar, aRemEnt, aRemCon);
652 if (!myTempConstraints.empty())
653 myStorage->verifyFixed();
654 myStorage->setNeedToResolve(false);
655 myTempConstraints.clear();
658 // ============================================================================
659 // Function: removeConstraint
660 // Class: SketchSolver_Group
661 // Purpose: remove constraint and all unused entities
662 // ============================================================================
663 void SketchSolver_Group::removeConstraint(ConstraintPtr theConstraint)
665 bool isFullyRemoved = true;
666 ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
667 for (; aCIter != myConstraints.end(); aCIter++)
668 if (aCIter->first == theConstraint) {
669 if (!aCIter->second->remove()) // the constraint is not fully removed
670 isFullyRemoved = false;
673 if (aCIter == myConstraints.end())
676 //// // Remove entities not used by constraints
677 //// myStorage->removeUnusedEntities();
680 myConstraints.erase(aCIter);
681 else if (aCIter != myConstraints.end() &&
682 aCIter->first->getKind() == SketchPlugin_ConstraintCoincidence::ID()) {
683 // Update multicoincidence
684 std::list<ConstraintPtr> aMultiCoinc;
685 SolverConstraintPtr aCoincidence = aCIter->second;
686 while (aCIter != myConstraints.end()) {
687 if (aCIter->second != aCoincidence) {
691 if (aCIter->first != theConstraint)
692 aMultiCoinc.push_back(aCIter->first);
693 aCIter->second->remove();
694 ConstraintConstraintMap::iterator aRemoveIt = aCIter++;
695 myConstraints.erase(aRemoveIt);
698 std::list<ConstraintPtr>::iterator anIt = aMultiCoinc.begin();
699 for (; anIt != aMultiCoinc.end(); ++anIt)
700 changeConstraint(*anIt);
702 notifyMultiConstraints();
706 // ============================================================================
707 // Function: isComplexConstraint
708 // Class: SketchSolver_Group
709 // Purpose: verifies the constraint is complex, i.e. it needs another constraints to be created before
710 // ============================================================================
711 bool SketchSolver_Group::isComplexConstraint(FeaturePtr theConstraint)
713 return theConstraint->getKind() == SketchPlugin_ConstraintFillet::ID() ||
714 theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID() ||
715 theConstraint->getKind() == SketchPlugin_ConstraintTangent::ID();
718 // ============================================================================
719 // Function: setTemporary
720 // Class: SketchSolver_Group
721 // Purpose: append given constraint to the group of temporary constraints
722 // ============================================================================
723 void SketchSolver_Group::setTemporary(SolverConstraintPtr theConstraint)
725 theConstraint->makeTemporary();
726 myTempConstraints.insert(theConstraint);
730 // ============================================================================
731 // Function: checkFeatureValidity
732 // Class: SketchSolver_Group
733 // Purpose: verifies is the feature valid
734 // ============================================================================
735 bool SketchSolver_Group::checkFeatureValidity(FeaturePtr theFeature)
737 if (!theFeature || !theFeature->data()->isValid())
740 SessionPtr aMgr = ModelAPI_Session::get();
741 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
742 return aFactory->validate(theFeature);
745 // ============================================================================
746 // Function: notifyMultiConstraints
747 // Class: SketchSolver_Group
748 // Purpose: Update Multi-Translation/-Rotation constraints due to multi coincidence appears/disappears
749 // ============================================================================
750 void SketchSolver_Group::notifyMultiConstraints()
752 //// ConstraintConstraintMap::iterator aCIter = myConstraints.begin();
753 //// for (; aCIter != myConstraints.end(); ++aCIter) {
754 //// if (aCIter->first->getKind() == SketchPlugin_MultiRotation::ID() ||
755 //// aCIter->first->getKind() == SketchPlugin_MultiTranslation::ID()) {
756 //// std::shared_ptr<SketchSolver_ConstraintMulti> aMulti =
757 //// std::dynamic_pointer_cast<SketchSolver_ConstraintMulti>(aCIter->second);
758 //// aMulti->checkCoincidence();
766 // =========== Auxiliary functions ========================================
767 static double featureToVal(FeaturePtr theFeature)
769 if (theFeature->getKind() == SketchPlugin_Sketch::ID())
770 return 0.0; // sketch
771 ConstraintPtr aConstraint = std::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
773 return 1.0; // features (arc, circle, line, point)
775 const std::string& anID = aConstraint->getKind();
776 if (anID == SketchPlugin_ConstraintCoincidence::ID()) {
777 AttributeRefAttrPtr anAttrA = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
778 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_A()));
779 AttributeRefAttrPtr anAttrB = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
780 aConstraint->attribute(SketchPlugin_Constraint::ENTITY_B()));
781 if (anAttrA && anAttrB && (anAttrA->isObject() || anAttrB->isObject()))
782 return 2.0; // point-on-line and point-on-circle should go before points coincidence constraint
785 if (anID == SketchPlugin_ConstraintDistance::ID() ||
786 anID == SketchPlugin_ConstraintLength::ID() ||
787 anID == SketchPlugin_ConstraintRadius::ID())
789 if (anID == SketchPlugin_ConstraintAngle::ID())
791 if (anID == SketchPlugin_ConstraintHorizontal::ID() ||
792 anID == SketchPlugin_ConstraintVertical::ID() ||
793 anID == SketchPlugin_ConstraintParallel::ID() ||
794 anID == SketchPlugin_ConstraintPerpendicular::ID())
796 if (anID == SketchPlugin_ConstraintEqual::ID())
798 if (anID == SketchPlugin_ConstraintTangent::ID() ||
799 anID == SketchPlugin_ConstraintMirror::ID())
801 if (anID == SketchPlugin_ConstraintRigid::ID())
803 if (anID == SketchPlugin_MultiRotation::ID() ||
804 anID == SketchPlugin_MultiTranslation::ID())
807 // all other constraints are placed between Equal and Tangent constraints
811 static bool isLess(FeaturePtr theFeature1, FeaturePtr theFeature2)
813 return featureToVal(theFeature1) < featureToVal(theFeature2);
816 std::list<FeaturePtr> SketchSolver_Group::selectApplicableFeatures(const std::set<ObjectPtr>& theObjects)
818 std::list<FeaturePtr> aResult;
819 std::list<FeaturePtr>::iterator aResIt;
821 std::set<ObjectPtr>::const_iterator anObjIter = theObjects.begin();
822 for (; anObjIter != theObjects.end(); ++anObjIter) {
823 // Operate sketch itself and SketchPlugin features only.
824 // Also, the Fillet need to be skipped, because there are several separated constraints composing it.
825 FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(*anObjIter);
828 std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
829 std::dynamic_pointer_cast<SketchPlugin_Feature>(aFeature);
830 if ((aFeature->getKind() != SketchPlugin_Sketch::ID() && !aSketchFeature) ||
831 aFeature->getKind() == SketchPlugin_ConstraintFillet::ID())
834 // Find the place where to insert a feature
835 for (aResIt = aResult.begin(); aResIt != aResult.end(); ++aResIt)
836 if (isLess(aFeature, *aResIt))
838 aResult.insert(aResIt, aFeature);