From: Alexey Kondratyev Date: Wed, 24 Nov 2021 06:10:08 +0000 (+0300) Subject: bos #24513 Dealing with conflicting constraints X-Git-Tag: V9_9_0a1~2^2 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=cdbbde4803e9c320204d537d22af4ac7ef024962;p=modules%2Fshaper.git bos #24513 Dealing with conflicting constraints * Add checkboxes to allow dealing with conflicting constraints and notify about changes with constraints. * Add class to resolve conflicting constrains. * Algorithm to check arcs in sketch on tangential conflict. * Move algorithm of vertical/horizontal auto constraint conflict in SketchPlugin_OverConstraintsResolver. --- diff --git a/doc/gui/General/Introduction.rst b/doc/gui/General/Introduction.rst index 3cb1c45b2..eea5fbf0f 100644 --- a/doc/gui/General/Introduction.rst +++ b/doc/gui/General/Introduction.rst @@ -618,11 +618,16 @@ Sketch tab defines properties of coordinate planes shown for selection of sketch - **Size** defines size of coordinate planes; - **Thickness** defines thickness of coordinate plane borders; -- **Rotate to plane when selected** check-box turns on/off automatic switch the viewer to the top view for the selected sketch plane. +- **Rotate to plane when selected** check-box turns on/off automatic switch the viewer to the top view for the selected sketch plane; - **Angular tolerance** defines defines an angular tolerance for automatic creation of horizontal and vertical constraints; - **Default spline weight** defines default weight for B-spline nodes during creation. The default value can be changed by editing of the spline; -- **Cursor for sketch operation** defines a cursor which indicates a launched sketcher sub-operation. +- **Cursor for sketch operation** defines a cursor which indicates a launched sketcher sub-operation; - **Create sketch entities by dragging** defines a style of sketch etities creation. It concerns creation of lines, rectangles, circles, arcs, ellipses, elliptic arcs. If it is switched ON then points of objects have to be defined by mouse press - mouse move - mouse release. Otherwise every point of an object has to be defined by mouse click; +- **Allow automatic constraint substitution/remove** allows automatic resolving of conflicting constraints. + The following conflicts could be processed: + - Horizontal/Vertical automatic constraints (this last constraint will be removed); + - Pair of arcs connected smoothly, which centers are coincident (Tangency between arcs will be removed); +- **Notify automatic constraint substitution/remove** defines a message box to be shown to the user, if the conflicting constraints situation is automatically resolved. .. _viewer_preferences: diff --git a/doc/gui/images/sketch_preferences.png b/doc/gui/images/sketch_preferences.png index 970444534..078058082 100755 Binary files a/doc/gui/images/sketch_preferences.png and b/doc/gui/images/sketch_preferences.png differ diff --git a/src/ModelAPI/ModelAPI_Events.cpp b/src/ModelAPI/ModelAPI_Events.cpp index 82d4c8e22..5734de4cd 100644 --- a/src/ModelAPI/ModelAPI_Events.cpp +++ b/src/ModelAPI/ModelAPI_Events.cpp @@ -471,6 +471,26 @@ const ListOfShape& ModelAPI_ShapesFailedMessage::shapes() const return myShapes; } +/// Creates an empty message +ModelAPI_CheckConstraintsMessage::ModelAPI_CheckConstraintsMessage(const Events_ID theID, const void* theSender) + :Events_Message(theID, theSender) +{ +} + +ModelAPI_CheckConstraintsMessage::~ModelAPI_CheckConstraintsMessage() +{ +} + +const std::set& ModelAPI_CheckConstraintsMessage::constraints() const +{ + return myConstraints; +} + +void ModelAPI_CheckConstraintsMessage::setConstraints(const std::set& theConstraints) +{ + myConstraints = theConstraints; +} + // ===== ModelAPI_FeaturesLicenseValidMessage ===== ModelAPI_FeaturesLicenseValidMessage::ModelAPI_FeaturesLicenseValidMessage( diff --git a/src/ModelAPI/ModelAPI_Events.h b/src/ModelAPI/ModelAPI_Events.h index 247f51bc3..efab2fae1 100644 --- a/src/ModelAPI/ModelAPI_Events.h +++ b/src/ModelAPI/ModelAPI_Events.h @@ -122,6 +122,10 @@ MAYBE_UNUSED static const char * EVENT_VISUAL_ATTRIBUTES = "UpdateVisualAttribut /// Event ID that 1D-fillet failed (comes with ModelAPI_ShapesFailedMessage) MAYBE_UNUSED static const char * EVENT_OPERATION_SHAPES_FAILED = "OperationShapesFailed"; +MAYBE_UNUSED static const char * EVENT_CHECK_CONSTRAINTS = "CheckConstrains"; + +MAYBE_UNUSED static const char * EVENT_REMOVE_CONSTRAINTS = "RemoveConstrains"; + /// Event ID that license of specified features is checked and valid MAYBE_UNUSED static const char * EVENT_FEATURE_LICENSE_VALID = "FeaturesLicenseValid"; @@ -659,6 +663,26 @@ private: std::list< std::shared_ptr > myShapes; }; +///Message that sends the constraints to check or remove +class ModelAPI_CheckConstraintsMessage : public Events_Message +{ +public: + /// Creates an empty message + MODELAPI_EXPORT ModelAPI_CheckConstraintsMessage(const Events_ID theID, const void* theSender = 0); + /// The virtual destructor + MODELAPI_EXPORT virtual ~ModelAPI_CheckConstraintsMessage(); + + ///Get list of constrains + MODELAPI_EXPORT const std::set& constraints() const; + + ///Set list of constrains + MODELAPI_EXPORT void setConstraints(const std::set& theConstraints); + +private: + std::set myConstraints; +}; + + /// Message that sends the features which license is checked and valid class ModelAPI_FeaturesLicenseValidMessage : public Events_Message { diff --git a/src/ModuleBase/ModuleBase_Preferences.cpp b/src/ModuleBase/ModuleBase_Preferences.cpp index 229603f83..d8d1c417a 100644 --- a/src/ModuleBase/ModuleBase_Preferences.cpp +++ b/src/ModuleBase/ModuleBase_Preferences.cpp @@ -118,6 +118,7 @@ void ModuleBase_Preferences::createEditContent(ModuleBase_IPrefMgr* thePref, int thePref->prefMgr()->setItemIcon(thePage, QIcon(":pictures/module.png")); createGeneralTab(thePref, thePage); createCustomPage(thePref, thePage); + updateSketchTab(thePref, thePage); } void ModuleBase_Preferences::resetResourcePreferences(SUIT_PreferenceMgr* thePref) @@ -210,6 +211,18 @@ void ModuleBase_Preferences::createGeneralTab(ModuleBase_IPrefMgr* thePref, int thePref->setItemProperty("indexes", visuIdList, visuId); } +void ModuleBase_Preferences::updateSketchTab(ModuleBase_IPrefMgr* thePref, int thePageId) +{ + int sketchTab = thePref->addPreference(QObject::tr("Sketch"), thePageId, + SUIT_PreferenceMgr::Auto, QString(), QString()); + int allowChange = thePref->addPreference( + QObject::tr("Allow automatic constraint substitution/remove"), + sketchTab, SUIT_PreferenceMgr::GroupBox, + "Sketch", "allow_change_constraint"); + thePref->addPreference(QObject::tr("Notify automatic constraint substitution/remove"), + allowChange, SUIT_PreferenceMgr::Bool, "Sketch", "notify_change_constraint"); +} + void ModuleBase_Preferences::createCustomPage(ModuleBase_IPrefMgr* thePref, int thePageId) { SUIT_ResourceMgr* aResMgr = ModuleBase_Preferences::resourceMgr(); diff --git a/src/ModuleBase/ModuleBase_Preferences.h b/src/ModuleBase/ModuleBase_Preferences.h index c35203768..787c4bb85 100644 --- a/src/ModuleBase/ModuleBase_Preferences.h +++ b/src/ModuleBase/ModuleBase_Preferences.h @@ -79,6 +79,9 @@ class MODULEBASE_EXPORT ModuleBase_Preferences /// Retrieve preferences of config prop to default state static void resetConfigPropPreferences(SUIT_PreferenceMgr* thePref); + /// Updates content of preferences for sketch tab + static void updateSketchTab(ModuleBase_IPrefMgr* thePref, int thePageId); + private: /// Updates SUIT_ResourceMgr values by Config_PropManager properties static void updateResourcesByConfig(); diff --git a/src/ModuleBase/ModuleBase_Tools.cpp b/src/ModuleBase/ModuleBase_Tools.cpp index bfe204d60..f1cf9f0d1 100644 --- a/src/ModuleBase/ModuleBase_Tools.cpp +++ b/src/ModuleBase/ModuleBase_Tools.cpp @@ -92,6 +92,7 @@ #include #include #include +#include #include #include @@ -1131,6 +1132,33 @@ bool askToDelete(const std::set theFeatures, return true; } +//************************************************************** +bool warningAboutConflict(QWidget* theParent, const std::string& theWarningText) +{ + QMessageBox aMessageBox(theParent); + aMessageBox.setWindowTitle(QObject::tr("Conflicts in constraint")); + aMessageBox.setIcon(QMessageBox::Warning); + aMessageBox.setText((theWarningText + "\nConstraints will be removed or substituted").c_str()); + + QCheckBox* aCheckBox = new QCheckBox; + + aCheckBox->setTristate(false); + aCheckBox->setText("switch off the notifications."); + + aMessageBox.setCheckBox(aCheckBox); + aMessageBox.setStandardButtons(QMessageBox::Ok); + + aMessageBox.exec(); + + if (aCheckBox->isChecked()) + { + ModuleBase_Preferences::resourceMgr()->setValue(SKETCH_TAB_NAME, + "notify_change_constraint", false); + } + + return true; +} + //************************************************************** void convertToFeatures(const QObjectPtrList& theObjects, std::set& theFeatures) { diff --git a/src/ModuleBase/ModuleBase_Tools.h b/src/ModuleBase/ModuleBase_Tools.h index cae27a1d9..23477a106 100644 --- a/src/ModuleBase/ModuleBase_Tools.h +++ b/src/ModuleBase/ModuleBase_Tools.h @@ -339,6 +339,11 @@ bool MODULEBASE_EXPORT askToDelete(const std::set aFeatures, std::set& theReferencesToDelete, const std::string& thePrefixInfo = ""); +/// Shows a message box about conflicting constraints. +/// \param theParent a parent widget for the message box +/// \param theWarningText text describing the cause of the conflict +bool MODULEBASE_EXPORT warningAboutConflict(QWidget* theParent, const std::string& theWarningText); + /// Converts a list of objects to set of corresponded features. If object is result, it is ignored /// because the feature only might be removed. But if result is in a parameter group, the feature /// of this parameter is to be removed diff --git a/src/PartSet/PartSet_Module.cpp b/src/PartSet/PartSet_Module.cpp index 70935fa37..f3e8ad1a5 100644 --- a/src/PartSet/PartSet_Module.cpp +++ b/src/PartSet/PartSet_Module.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include #include @@ -149,6 +150,7 @@ #include #include +#include #define FEATURE_ITEM_COLOR "0,0,225" @@ -1983,28 +1985,54 @@ void PartSet_Module::enableCustomModes() { } //****************************************************** -void PartSet_Module::onConflictingConstraints() +void PartSet_Module::onRemoveConflictingConstraints() { - const std::set& aConstraints = myOverconstraintListener->conflictingObjects(); - QObjectPtrList aObjectsList; - std::set::const_iterator aIt; - for (aIt = aConstraints.cbegin(); aIt != aConstraints.cend(); aIt++) { - if (mySketchReentrantMgr->isLastAutoConstraint(*aIt)) - aObjectsList.append(*aIt); + const std::set& aConstraints = myOverconstraintListener->objectsToRemove(); + std::set::const_iterator anIt; + + XGUI_Workshop* aWorkshop = getWorkshop(); + XGUI_OperationMgr* anOpMgr = aWorkshop->operationMgr(); + + bool isAllowToNotify = ModuleBase_Preferences::resourceMgr()->booleanValue(SKETCH_TAB_NAME, + "notify_change_constraint"); + + if (isAllowToNotify) { + anIt = aConstraints.begin(); + std::string aText("Conflict in constraints: \n"); + + for (; anIt != aConstraints.end(); anIt++) + { + ObjectPtr anObject = *anIt; + FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); + TCollection_AsciiString aStr(aFeature->name().c_str()); + std::string aName(aStr.ToCString()); + aText += aName + "\n"; + } + + XGUI_ModuleConnector* aConnector = dynamic_cast(myWorkshop); + ModuleBase_Tools::warningAboutConflict(aConnector->desktop(), + aText); } - if (aObjectsList.size() > 0) { - XGUI_Workshop* aWorkshop = getWorkshop(); + + ModuleBase_Operation* anOp = anOpMgr->currentOperation(); + if (sketchMgr()->isNestedSketchOperation(anOp)) { + std::set aFeatures; + for (anIt = aConstraints.cbegin(); anIt != aConstraints.cend(); anIt++) + aFeatures.insert(ModelAPI_Feature::feature(*anIt)); + + ModelAPI_Tools::removeFeaturesAndReferences(aFeatures); + } + else { + QObjectPtrList anObjectsList; + for (anIt = aConstraints.cbegin(); anIt != aConstraints.cend(); anIt++) + anObjectsList.append(*anIt); + QString aDescription = aWorkshop->contextMenuMgr()->action("DELETE_CMD")->text(); ModuleBase_Operation* anOpAction = new ModuleBase_Operation(aDescription); - XGUI_OperationMgr* anOpMgr = aWorkshop->operationMgr(); - - ModuleBase_Operation* anOp = anOpMgr->currentOperation(); - if (sketchMgr()->isNestedSketchOperation(anOp)) - anOp->abort(); anOpMgr->startOperation(anOpAction); - aWorkshop->deleteFeatures(aObjectsList); + aWorkshop->deleteFeatures(anObjectsList); anOpMgr->commitOperation(); - ModuleBase_Tools::flushUpdated(sketchMgr()->activeSketch()); } + ModuleBase_Tools::flushUpdated(sketchMgr()->activeSketch()); } diff --git a/src/PartSet/PartSet_Module.h b/src/PartSet/PartSet_Module.h index 7a39b8998..377ac23b7 100644 --- a/src/PartSet/PartSet_Module.h +++ b/src/PartSet/PartSet_Module.h @@ -417,7 +417,8 @@ public slots: /// \param theTrsfType type of tranformation virtual void onViewTransformed(int theTrsfType = 2); - void onConflictingConstraints(); + /// Called on remove conflicting constraints + void onRemoveConflictingConstraints(); protected slots: /// Called when previous operation is finished diff --git a/src/PartSet/PartSet_OverconstraintListener.cpp b/src/PartSet/PartSet_OverconstraintListener.cpp index 656593d9b..5db78193f 100644 --- a/src/PartSet/PartSet_OverconstraintListener.cpp +++ b/src/PartSet/PartSet_OverconstraintListener.cpp @@ -20,6 +20,10 @@ #include #include +// Attention: keep the next include here, +// otherwise it causes compilation errors at least on Debian 8 +#include + #include "PartSet_OverconstraintListener.h" #include #include @@ -38,6 +42,8 @@ #include "SketchPlugin_ConstraintHorizontal.h" #include "SketchPlugin_ConstraintVertical.h" +#include + #include "Events_Loop.h" #include @@ -62,6 +68,7 @@ PartSet_OverconstraintListener::PartSet_OverconstraintListener(ModuleBase_IWorks aLoop->registerListener(this, ModelAPI_EventReentrantMessage::eventId()); aLoop->registerListener(this, SketchPlugin_MacroArcReentrantMessage::eventId()); + aLoop->registerListener(this, Events_Loop::eventByName(EVENT_REMOVE_CONSTRAINTS)); } void PartSet_OverconstraintListener::setActive(const bool& theActive) @@ -225,7 +232,34 @@ void PartSet_OverconstraintListener::processEvent(const std::shared_ptr aConstraintsMsg = + std::dynamic_pointer_cast(theMessage); + if (aConstraintsMsg.get()) { + myObjectsToRemove = aConstraintsMsg->constraints(); + + std::set::const_iterator + anIt = myObjectsToRemove.begin(), aLast = myObjectsToRemove.end(); + + PartSet_Module* aModule = dynamic_cast(myWorkshop->module()); + + for (; anIt != aLast; anIt++) + { + ObjectPtr anObject = *anIt; + FeaturePtr aFeature = std::dynamic_pointer_cast(anObject); + std::string aType = aFeature->getKind(); + if ((aType == SketchPlugin_ConstraintHorizontal::ID() || + aType == SketchPlugin_ConstraintVertical::ID()) && + !aModule->sketchReentranceMgr()->isLastAutoConstraint(*anIt)) + myObjectsToRemove.erase(*anIt); + } + + if (myObjectsToRemove.empty()) + return; + QTimer::singleShot(5, aModule, SLOT(onRemoveConflictingConstraints())); + } + } #ifdef DEBUG_FEATURE_OVERCONSTRAINT_LISTENER aCurrentInfoStr = getObjectsInfo(myConflictingObjects); qDebug(QString("RESULT: current objects count = %1:%2\n") @@ -236,40 +270,43 @@ void PartSet_OverconstraintListener::processEvent(const std::shared_ptr& theConflictingObjects) { - std::set aModifiedObjects; - - // set error state for new objects and append them in the internal map of objects - std::set::const_iterator - anIt = theConflictingObjects.begin(), aLast = theConflictingObjects.end(); - FeaturePtr aFeature; - bool isHVConstraint = false; - for (; anIt != aLast; anIt++) { - ObjectPtr anObject = *anIt; - if (myConflictingObjects.find(anObject) == myConflictingObjects.end()) { // it is not found - aModifiedObjects.insert(anObject); - myConflictingObjects.insert(anObject); - } - if (!isHVConstraint) { - aFeature = std::dynamic_pointer_cast(anObject); - if (aFeature) { - std::string aType = aFeature->getKind(); - isHVConstraint = (aType == SketchPlugin_ConstraintHorizontal::ID()) || - (aType == SketchPlugin_ConstraintVertical::ID()); + bool isAllowToChange = ModuleBase_Preferences::resourceMgr()->booleanValue(SKETCH_TAB_NAME, + "allow_change_constraint"); + if (isAllowToChange) { + std::set aModifiedObjects; + + // set error state for new objects and append them in the internal map of objects + std::set::const_iterator + anIt = theConflictingObjects.begin(), aLast = theConflictingObjects.end(); + + int aCountOfSimilarConstraints = 0; + for (; anIt != aLast; anIt++) { + ObjectPtr anObject = *anIt; + if (myConflictingObjects.find(anObject) == myConflictingObjects.end()) { // it is not found + aModifiedObjects.insert(anObject); + myConflictingObjects.insert(anObject); } + else + ++aCountOfSimilarConstraints; } - } - bool isUpdated = !aModifiedObjects.empty(); - if (isUpdated) - redisplayObjects(aModifiedObjects); - // If the conflicting object is an automatic constraint caused the conflict - // then it has to be deleted - if (isHVConstraint) { - PartSet_Module* aModule = dynamic_cast(myWorkshop->module()); - QTimer::singleShot(5, aModule, SLOT(onConflictingConstraints())); - } + if (theConflictingObjects.size() == aCountOfSimilarConstraints) + return false; - return isUpdated; + std::shared_ptr aMessage = + std::shared_ptr( + new ModelAPI_CheckConstraintsMessage( + Events_Loop::eventByName(EVENT_CHECK_CONSTRAINTS))); + aMessage->setConstraints(theConflictingObjects); + Events_Loop::loop()->send(aMessage); + + bool isUpdated = !aModifiedObjects.empty(); + if (isUpdated) + redisplayObjects(aModifiedObjects); + return isUpdated; + } + else + return false; } bool PartSet_OverconstraintListener::repairConflictingObjects( diff --git a/src/PartSet/PartSet_OverconstraintListener.h b/src/PartSet/PartSet_OverconstraintListener.h index a0f2fed6e..910527051 100644 --- a/src/PartSet/PartSet_OverconstraintListener.h +++ b/src/PartSet/PartSet_OverconstraintListener.h @@ -69,6 +69,11 @@ public: return myConflictingObjects; } + const std::set& objectsToRemove() const + { + return myObjectsToRemove; + } + bool isFullyConstrained() const { return myIsFullyConstrained; } protected: @@ -101,6 +106,7 @@ private: ModuleBase_IWorkshop* myWorkshop; bool myIsActive; /// state if sketch is active std::set myConflictingObjects; + std::set myObjectsToRemove; bool myIsFullyConstrained; /// state if Solver is fully constrained, DOF = 0 }; diff --git a/src/SHAPERGUI/resources/LightApp.xml.in b/src/SHAPERGUI/resources/LightApp.xml.in index 0a0028ab8..76fed3d33 100644 --- a/src/SHAPERGUI/resources/LightApp.xml.in +++ b/src/SHAPERGUI/resources/LightApp.xml.in @@ -28,6 +28,11 @@ +
+ + + +
diff --git a/src/SketchPlugin/CMakeLists.txt b/src/SketchPlugin/CMakeLists.txt index 2fd3420d0..98c0ead1e 100644 --- a/src/SketchPlugin/CMakeLists.txt +++ b/src/SketchPlugin/CMakeLists.txt @@ -65,6 +65,7 @@ SET(PROJECT_HEADERS SketchPlugin_MultiRotation.h SketchPlugin_MultiTranslation.h SketchPlugin_Offset.h + SketchPlugin_OverConstraintsResolver.h SketchPlugin_Plugin.h SketchPlugin_Point.h SketchPlugin_Projection.h @@ -120,6 +121,7 @@ SET(PROJECT_SOURCES SketchPlugin_MultiRotation.cpp SketchPlugin_MultiTranslation.cpp SketchPlugin_Offset.cpp + SketchPlugin_OverConstraintsResolver.cpp SketchPlugin_Plugin.cpp SketchPlugin_Point.cpp SketchPlugin_Projection.cpp diff --git a/src/SketchPlugin/SketchPlugin_OverConstraintsResolver.cpp b/src/SketchPlugin/SketchPlugin_OverConstraintsResolver.cpp new file mode 100644 index 000000000..e54da2688 --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_OverConstraintsResolver.cpp @@ -0,0 +1,187 @@ +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static SketchPlugin_OverConstraintsResolver* myConstResolver = + new SketchPlugin_OverConstraintsResolver; + +SketchPlugin_OverConstraintsResolver::SketchPlugin_OverConstraintsResolver() +{ + Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_CHECK_CONSTRAINTS)); +} + +void SketchPlugin_OverConstraintsResolver::setConstraints( + const std::set& theConstraints) +{ + myConstraints = theConstraints; +} + +bool SketchPlugin_OverConstraintsResolver::perform() +{ + bool hasConflicts = false; + hasConflicts |= checkArcsAboutTangentialConflict(); + hasConflicts |= checkHorizontalOrVerticalConflict(); + return hasConflicts; +} + +bool SketchPlugin_OverConstraintsResolver::checkHorizontalOrVerticalConflict() +{ + std::set::const_iterator + anIt = myConstraints.begin(), aLast = myConstraints.end(); + bool isHVConstraint = false; + FeaturePtr aFeature; + for (; anIt != aLast; anIt++) { + ObjectPtr anObject = *anIt; + if (!isHVConstraint) { + aFeature = std::dynamic_pointer_cast(anObject); + if (aFeature) { + std::string aType = aFeature->getKind(); + if ((aType == SketchPlugin_ConstraintHorizontal::ID()) || + (aType == SketchPlugin_ConstraintVertical::ID())) + { + myConstraintsToRemove.insert(*anIt); + isHVConstraint = true; + } + } + } + } + return isHVConstraint; +} + +bool SketchPlugin_OverConstraintsResolver::checkArcsAboutTangentialConflict() +{ + bool isConflictsFound = false; + + std::set::const_iterator + anIt = myConstraints.begin(), aLast = myConstraints.end(); + for (; anIt != aLast; anIt++) { + ObjectPtr anObject = *anIt; + ConstraintPtr aConstain = + std::dynamic_pointer_cast(anObject); + if (aConstain.get()) { + std::shared_ptr aRefAttrA = aConstain->refattr( + aConstain->ENTITY_A()); + std::shared_ptr aRefAttrB = aConstain->refattr( + aConstain->ENTITY_B()); + if (!aRefAttrA || !aRefAttrB) + continue; + + FeaturePtr aFeatureA = ModelAPI_Feature::feature(aRefAttrA->object()); + FeaturePtr aFeatureB = ModelAPI_Feature::feature(aRefAttrB->object()); + + if (aFeatureA && aFeatureA->getKind() == SketchPlugin_Arc::ID() && + aFeatureB && aFeatureB->getKind() == SketchPlugin_Arc::ID()) { + + std::shared_ptr anAttrStrA = aFeatureA->attribute( + SketchPlugin_Arc::START_ID()); + std::shared_ptr anAttrEndA = aFeatureA->attribute( + SketchPlugin_Arc::END_ID()); + std::shared_ptr anAttrStrB = aFeatureB->attribute( + SketchPlugin_Arc::START_ID()); + std::shared_ptr anAttrEndB = aFeatureB->attribute( + SketchPlugin_Arc::END_ID()); + std::shared_ptr anAttrCenA = aFeatureA->attribute( + SketchPlugin_Arc::CENTER_ID()); + std::shared_ptr anAttrCenB = aFeatureB->attribute( + SketchPlugin_Arc::CENTER_ID()); + + bool isCoincident = false; + bool isCoincidentAtCenter = false; + std::set aTangentConstraints; + + std::set aFeatures; + std::map > aFeaturesMap; + aFeatures.insert(aFeatureA); + aFeatures.insert(aFeatureB); + ModelAPI_Tools::findAllReferences(aFeatures, aFeaturesMap); + + std::set aFeaturesA = aFeaturesMap[aFeatureA]; + std::set aFeaturesB = aFeaturesMap[aFeatureB]; + + for (auto aFeatIter = aFeaturesA.begin(); aFeatIter != aFeaturesA.end(); ++aFeatIter) { + if (aFeaturesB.find(aFeatIter.operator*()) != aFeaturesB.end()){ + const std::string& aType = (*aFeatIter)->getKind(); + if (aType == SketchPlugin_ConstraintCoincidence::ID()) { + ConstraintPtr aCoincidence = + std::dynamic_pointer_cast(*aFeatIter); + std::set anAttrSet; + anAttrSet.insert(aCoincidence->refattr(aCoincidence->ENTITY_A())->attr()); + anAttrSet.insert(aCoincidence->refattr(aCoincidence->ENTITY_B())->attr()); + isCoincident |= ((anAttrSet.find(anAttrStrA) != anAttrSet.end() || + anAttrSet.find(anAttrEndA) != anAttrSet.end()) && + (anAttrSet.find(anAttrStrB) != anAttrSet.end() || + anAttrSet.find(anAttrEndB) != anAttrSet.end())); + isCoincidentAtCenter |= (anAttrSet.find(anAttrCenA) != anAttrSet.end() && + anAttrSet.find(anAttrCenB) != anAttrSet.end()); + } + else if (aType == SketchPlugin_ConstraintTangent::ID()) { + aTangentConstraints.insert(*aFeatIter); + } + } + } + + if (isCoincident && isCoincidentAtCenter && !aTangentConstraints.empty()) { + isConflictsFound = true; + myConstraintsToRemove.insert(aTangentConstraints.begin(), aTangentConstraints.end()); + } + } + } + } + + return isConflictsFound; +} + +void SketchPlugin_OverConstraintsResolver::processEvent( + const std::shared_ptr& theMessage) +{ + Events_ID anEventID = theMessage->eventID(); + if (anEventID == Events_Loop::eventByName(EVENT_CHECK_CONSTRAINTS)) { + std::shared_ptr aConstraintsMsg = + std::dynamic_pointer_cast(theMessage); + if (aConstraintsMsg.get()) { + myConstraintsToRemove.clear(); + myConstraints = aConstraintsMsg->constraints(); + if (perform()) + { + std::shared_ptr aMessage = + std::shared_ptr( + new ModelAPI_CheckConstraintsMessage( + Events_Loop::eventByName(EVENT_REMOVE_CONSTRAINTS))); + aMessage->setConstraints(myConstraintsToRemove); + Events_Loop::loop()->send(aMessage); + } + } + } +} diff --git a/src/SketchPlugin/SketchPlugin_OverConstraintsResolver.h b/src/SketchPlugin/SketchPlugin_OverConstraintsResolver.h new file mode 100644 index 000000000..88eca4e0c --- /dev/null +++ b/src/SketchPlugin/SketchPlugin_OverConstraintsResolver.h @@ -0,0 +1,58 @@ +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef SketchPlugin_OverConstraintsResolver_H_ +#define SketchPlugin_OverConstraintsResolver_H_ + +#include "SketchPlugin.h" + +#include + +#include + +#include + +class SketchPlugin_OverConstraintsResolver : public Events_Listener +{ +public: + SketchPlugin_OverConstraintsResolver(); + + /// Redefinition of Events_Listener method + void processEvent(const std::shared_ptr& theMessage); + + virtual bool groupMessages() { return true; } + +protected: + /// Perform algorithm + bool perform(); + + /// Set set of constraints to check + void setConstraints(const std::set& theConstraints); + + /// Check arcs in sketch about tangential conflict + bool checkArcsAboutTangentialConflict(); + + /// Check lines in sketch about horizontal or vertical conflict + bool checkHorizontalOrVerticalConflict(); + +private: + std::set myConstraints; + std::set myConstraintsToRemove; +}; +#endif diff --git a/src/XGUI/SHAPER.xml b/src/XGUI/SHAPER.xml index 94ff4fcc6..ed65fcec5 100644 --- a/src/XGUI/SHAPER.xml +++ b/src/XGUI/SHAPER.xml @@ -10,6 +10,11 @@
+
+ + + +
@@ -42,5 +47,4 @@
-