Salome HOME
bos #24513 Dealing with conflicting constraints
authorAlexey Kondratyev <alexey.kondratyev@opencascade.com>
Wed, 24 Nov 2021 06:10:08 +0000 (09:10 +0300)
committervsr <vsr@opencascade.com>
Fri, 25 Feb 2022 08:20:29 +0000 (11:20 +0300)
* 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.

17 files changed:
doc/gui/General/Introduction.rst
doc/gui/images/sketch_preferences.png
src/ModelAPI/ModelAPI_Events.cpp
src/ModelAPI/ModelAPI_Events.h
src/ModuleBase/ModuleBase_Preferences.cpp
src/ModuleBase/ModuleBase_Preferences.h
src/ModuleBase/ModuleBase_Tools.cpp
src/ModuleBase/ModuleBase_Tools.h
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_Module.h
src/PartSet/PartSet_OverconstraintListener.cpp
src/PartSet/PartSet_OverconstraintListener.h
src/SHAPERGUI/resources/LightApp.xml.in
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_OverConstraintsResolver.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_OverConstraintsResolver.h [new file with mode: 0644]
src/XGUI/SHAPER.xml

index 3cb1c45b2098d74de2805449301855a62836a0d1..eea5fbf0fa7c56f4c253a0fbc393b016a2a56dd4 100644 (file)
@@ -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:
 
index 97044453421fc016cba30a4b6c4f5eef973b6563..0780580827815d693830cd163c158232b3b3dfa4 100755 (executable)
Binary files a/doc/gui/images/sketch_preferences.png and b/doc/gui/images/sketch_preferences.png differ
index 82d4c8e22b51c624ad164f7085c5678c384efd5d..5734de4cd83a025b3c4812ba238acb05ab9ffefb 100644 (file)
@@ -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<ObjectPtr>& ModelAPI_CheckConstraintsMessage::constraints() const
+{
+  return myConstraints;
+}
+
+void ModelAPI_CheckConstraintsMessage::setConstraints(const std::set<ObjectPtr>& theConstraints)
+{
+  myConstraints = theConstraints;
+}
+
 
 // =====   ModelAPI_FeaturesLicenseValidMessage   =====
 ModelAPI_FeaturesLicenseValidMessage::ModelAPI_FeaturesLicenseValidMessage(
index 247f51bc3cb1422429b60b19077425c8d8a4d466..efab2fae163aff554e4dcf6fd8ea09c8c18bd01b 100644 (file)
@@ -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<GeomAPI_Shape> > 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<ObjectPtr>& constraints() const;
+
+  ///Set list of constrains
+  MODELAPI_EXPORT void setConstraints(const std::set<ObjectPtr>& theConstraints);
+
+private:
+  std::set<ObjectPtr> myConstraints;
+};
+
+
 /// Message that sends the features which license is checked and valid
 class ModelAPI_FeaturesLicenseValidMessage : public Events_Message
 {
index 229603f834503abe506ae7dbab73070b643a1c3c..d8d1c417a238bac26a17596c3a36de34feaedb43 100644 (file)
@@ -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();
index c3520376874dfcd78ac2d7f3b07bbc287ac17b2d..787c4bb85df0bb11dbd00e723c34b382509aae00 100644 (file)
@@ -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();
index bfe204d60cf278870243211732e4f9f79f2415b3..f1cf9f0d12733065ee1865167bf0565d514319ce 100644 (file)
@@ -92,6 +92,7 @@
 #include <QTextCodec>
 #include <QWindow>
 #include <QScreen>
+#include <QCheckBox>
 
 #include <sstream>
 #include <string>
@@ -1131,6 +1132,33 @@ bool askToDelete(const std::set<FeaturePtr> 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<FeaturePtr>& theFeatures)
 {
index cae27a1d92115896c1f223a498b840234e95a1fa..23477a106afe2e5218320747bc62ec6dcd880e83 100644 (file)
@@ -339,6 +339,11 @@ bool MODULEBASE_EXPORT askToDelete(const std::set<FeaturePtr> aFeatures,
                                    std::set<FeaturePtr>& 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
index 70935fa37dcf2b7ada4632aaeeb8182c8d87bebf..f3e8ad1a568369c21bcc6d2a90331223fa328225 100644 (file)
@@ -69,6 +69,7 @@
 #include <ModuleBase_OperationDescription.h>
 #include <ModuleBase_ViewerPrs.h>
 #include <ModuleBase_ResultPrs.h>
+#include <ModuleBase_Preferences.h>
 
 #include <ModelAPI_ResultField.h>
 #include <ModelAPI_Object.h>
 #include <SelectMgr_ListIteratorOfListOfFilter.hxx>
 #include <Graphic3d_Texture2Dmanual.hxx>
 
+#include <SUIT_ResourceMgr.h>
 
 #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<ObjectPtr>& aConstraints = myOverconstraintListener->conflictingObjects();
-  QObjectPtrList aObjectsList;
-  std::set<ObjectPtr>::const_iterator aIt;
-  for (aIt = aConstraints.cbegin(); aIt != aConstraints.cend(); aIt++) {
-    if (mySketchReentrantMgr->isLastAutoConstraint(*aIt))
-      aObjectsList.append(*aIt);
+  const std::set<ObjectPtr>& aConstraints = myOverconstraintListener->objectsToRemove();
+  std::set<ObjectPtr>::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<ModelAPI_Feature>(anObject);
+      TCollection_AsciiString aStr(aFeature->name().c_str());
+      std::string aName(aStr.ToCString());
+      aText += aName + "\n";
+    }
+
+    XGUI_ModuleConnector* aConnector = dynamic_cast<XGUI_ModuleConnector*>(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<FeaturePtr> 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());
 }
index 7a39b899847fb6306959c1e2b1d6873e2638b8b4..377ac23b7ae85a9c08b283ec8f9c5307131f49af 100644 (file)
@@ -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
index 656593d9b5348f6c29fc554627f6d406c2002872..5db78193f6a92f367f127386aa3415f9668404ea 100644 (file)
 #include <ModelAPI_Tools.h>
 #include <ModelAPI_AttributeString.h>
 
+// Attention: keep the next include here,
+// otherwise it causes compilation errors at least on Debian 8
+#include <ModuleBase_Preferences.h>
+
 #include "PartSet_OverconstraintListener.h"
 #include <PartSet_Module.h>
 #include <PartSet_SketcherMgr.h>
@@ -38,6 +42,8 @@
 #include "SketchPlugin_ConstraintHorizontal.h"
 #include "SketchPlugin_ConstraintVertical.h"
 
+#include <SUIT_ResourceMgr.h>
+
 #include "Events_Loop.h"
 
 #include <GeomAPI_IPresentable.h>
@@ -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<Events_M
       }
     }
   }
+  else if (anEventID == Events_Loop::eventByName(EVENT_REMOVE_CONSTRAINTS)) {
+    std::shared_ptr<ModelAPI_CheckConstraintsMessage> aConstraintsMsg =
+      std::dynamic_pointer_cast<ModelAPI_CheckConstraintsMessage>(theMessage);
+    if (aConstraintsMsg.get()) {
+      myObjectsToRemove = aConstraintsMsg->constraints();
+
+      std::set<ObjectPtr>::const_iterator
+        anIt = myObjectsToRemove.begin(), aLast = myObjectsToRemove.end();
+
+      PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+
+      for (; anIt != aLast; anIt++)
+      {
+        ObjectPtr anObject = *anIt;
+        FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(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<Events_M
 bool PartSet_OverconstraintListener::appendConflictingObjects(
                                                const std::set<ObjectPtr>& theConflictingObjects)
 {
-  std::set<ObjectPtr> aModifiedObjects;
-
-  // set error state for new objects and append them in the internal map of objects
-  std::set<ObjectPtr>::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<ModelAPI_Feature>(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<ObjectPtr> aModifiedObjects;
+
+    // set error state for new objects and append them in the internal map of objects
+    std::set<ObjectPtr>::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<PartSet_Module*>(myWorkshop->module());
-    QTimer::singleShot(5, aModule, SLOT(onConflictingConstraints()));
-  }
+    if (theConflictingObjects.size() == aCountOfSimilarConstraints)
+      return false;
 
-  return isUpdated;
+    std::shared_ptr<ModelAPI_CheckConstraintsMessage> aMessage =
+      std::shared_ptr<ModelAPI_CheckConstraintsMessage>(
+        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(
index a0f2fed6ea7277d5f0e8a9ab7a9203637f2fdb33..9105270516dbe0b469ccac558bbeb03cb0eef4bc 100644 (file)
@@ -69,6 +69,11 @@ public:
     return myConflictingObjects;
   }
 
+  const std::set<ObjectPtr>& 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<ObjectPtr> myConflictingObjects;
+  std::set<ObjectPtr> myObjectsToRemove;
   bool myIsFullyConstrained; /// state if Solver is fully constrained, DOF = 0
 };
 
index 0a0028ab87e15d8f8f2664b16057aba2e44caabc..76fed3d33874dc571d2948f5e656c037c8a96718 100644 (file)
     <parameter name="part_visualization_study" value="0"/>
     <parameter name="part_visualization_script" value="1"/>
   </section>
+  <section name="Sketch">
+    <!-- Sketch preferences -->
+    <parameter name="allow_change_constraint" value="true"/>
+    <parameter name="notify_change_constraint" value="true"/>
+  </section>
   <section name="Viewer" >
     <!-- Viewer preferences -->
     <parameter name="face-selection" value="true" />
index 2fd3420d0757eecbcb8d19c251dd94607b08b2bf..98c0ead1eff22ad3cca0435ea08b941b698d34bb 100644 (file)
@@ -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 (file)
index 0000000..e54da26
--- /dev/null
@@ -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 <SketchPlugin_OverConstraintsResolver.h>
+
+#include <Events_Loop.h>
+
+#include <ModelAPI_Attribute.h>
+#include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_Feature.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Tools.h>
+
+#include <SketchPlugin_Arc.h>
+#include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintTangent.h>
+#include <SketchPlugin_ConstraintHorizontal.h>
+#include <SketchPlugin_ConstraintVertical.h>
+#include <SketchPlugin_Point.h>
+
+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<ObjectPtr>& theConstraints)
+{
+  myConstraints = theConstraints;
+}
+
+bool SketchPlugin_OverConstraintsResolver::perform()
+{
+  bool hasConflicts = false;
+  hasConflicts |= checkArcsAboutTangentialConflict();
+  hasConflicts |= checkHorizontalOrVerticalConflict();
+  return hasConflicts;
+}
+
+bool SketchPlugin_OverConstraintsResolver::checkHorizontalOrVerticalConflict()
+{
+  std::set<ObjectPtr>::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<ModelAPI_Feature>(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<ObjectPtr>::const_iterator
+    anIt = myConstraints.begin(), aLast = myConstraints.end();
+  for (; anIt != aLast; anIt++) {
+    ObjectPtr anObject = *anIt;
+    ConstraintPtr aConstain =
+      std::dynamic_pointer_cast<SketchPlugin_Constraint>(anObject);
+    if (aConstain.get()) {
+      std::shared_ptr<ModelAPI_AttributeRefAttr> aRefAttrA = aConstain->refattr(
+                                                             aConstain->ENTITY_A());
+      std::shared_ptr<ModelAPI_AttributeRefAttr> 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<ModelAPI_Attribute> anAttrStrA = aFeatureA->attribute(
+                                                         SketchPlugin_Arc::START_ID());
+        std::shared_ptr<ModelAPI_Attribute> anAttrEndA = aFeatureA->attribute(
+                                                         SketchPlugin_Arc::END_ID());
+        std::shared_ptr<ModelAPI_Attribute> anAttrStrB = aFeatureB->attribute(
+                                                         SketchPlugin_Arc::START_ID());
+        std::shared_ptr<ModelAPI_Attribute> anAttrEndB = aFeatureB->attribute(
+                                                         SketchPlugin_Arc::END_ID());
+        std::shared_ptr<ModelAPI_Attribute> anAttrCenA = aFeatureA->attribute(
+                                                         SketchPlugin_Arc::CENTER_ID());
+        std::shared_ptr<ModelAPI_Attribute> anAttrCenB = aFeatureB->attribute(
+                                                         SketchPlugin_Arc::CENTER_ID());
+
+        bool isCoincident = false;
+        bool isCoincidentAtCenter = false;
+        std::set<FeaturePtr> aTangentConstraints;
+
+        std::set<FeaturePtr> aFeatures;
+        std::map<FeaturePtr, std::set<FeaturePtr> > aFeaturesMap;
+        aFeatures.insert(aFeatureA);
+        aFeatures.insert(aFeatureB);
+        ModelAPI_Tools::findAllReferences(aFeatures, aFeaturesMap);
+
+        std::set<FeaturePtr> aFeaturesA = aFeaturesMap[aFeatureA];
+        std::set<FeaturePtr> 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<SketchPlugin_ConstraintCoincidence>(*aFeatIter);
+              std::set<AttributePtr> 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<Events_Message>& theMessage)
+{
+  Events_ID anEventID = theMessage->eventID();
+  if (anEventID == Events_Loop::eventByName(EVENT_CHECK_CONSTRAINTS)) {
+    std::shared_ptr<ModelAPI_CheckConstraintsMessage> aConstraintsMsg =
+      std::dynamic_pointer_cast<ModelAPI_CheckConstraintsMessage>(theMessage);
+    if (aConstraintsMsg.get()) {
+      myConstraintsToRemove.clear();
+      myConstraints = aConstraintsMsg->constraints();
+      if (perform())
+      {
+        std::shared_ptr<ModelAPI_CheckConstraintsMessage> aMessage =
+          std::shared_ptr<ModelAPI_CheckConstraintsMessage>(
+            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 (file)
index 0000000..88eca4e
--- /dev/null
@@ -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 <Events_Listener.h>
+
+#include <ModelAPI_Object.h>
+
+#include <set>
+
+class SketchPlugin_OverConstraintsResolver : public Events_Listener
+{
+public:
+  SketchPlugin_OverConstraintsResolver();
+
+  /// Redefinition of Events_Listener method
+  void processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+  virtual bool groupMessages() { return true; }
+
+protected:
+  /// Perform algorithm
+  bool perform();
+
+  /// Set set of constraints to check
+  void setConstraints(const std::set<ObjectPtr>& theConstraints);
+
+  /// Check arcs in sketch about tangential conflict
+  bool checkArcsAboutTangentialConflict();
+
+  /// Check lines in sketch about horizontal or vertical conflict
+  bool checkHorizontalOrVerticalConflict();
+
+private:
+  std::set<ObjectPtr> myConstraints;
+  std::set<ObjectPtr> myConstraintsToRemove;
+};
+#endif
index 94ff4fcc67ccd25b3ed3aab3eee02339243ac1aa..ed65fcec5c7b7b5448a2d616d08ccc736c8f5a9b 100644 (file)
     <parameter name="part_visualization_study" value="0"/>
     <parameter name="part_visualization_script" value="1"/>
   </section>
+  <section name="Sketch">
+    <!-- Sketch preferences -->
+    <parameter name="allow_change_constraint" value="true"/>
+    <parameter name="notify_change_constraint" value="true"/>
+  </section>
   <section name="Viewer" >
     <!-- Viewer preferences -->
     <parameter name="background" value="bt=2;fn=;tm=0;ts=false;c1=#cddbff;c2=#698fff;gt=1;gr=" />
@@ -42,5 +47,4 @@
     <parameter name="winapplication"       value="C:\Program Files\Internet Explorer\iexplore.exe" />
     <parameter name="application"          value="/usr/bin/mozilla" />
   </section>
-
 </document>