]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge branch 'Dev_1.1.0' of newgeom:newgeom into Dev_1.1.0
authornds <natalia.donis@opencascade.com>
Thu, 19 Mar 2015 07:11:24 +0000 (10:11 +0300)
committernds <natalia.donis@opencascade.com>
Thu, 19 Mar 2015 07:11:24 +0000 (10:11 +0300)
20 files changed:
src/InitializationPlugin/InitializationPlugin_Plugin.cpp
src/InitializationPlugin/InitializationPlugin_Plugin.h
src/Model/Model_Data.cpp
src/Model/Model_Data.h
src/ModelAPI/ModelAPI_Data.h
src/ModelAPI/ModelAPI_Events.h
src/ModuleBase/ModuleBase_PageBase.h
src/ModuleBase/ModuleBase_PageGroupBox.h
src/ModuleBase/ModuleBase_PageWidget.h
src/ModuleBase/ModuleBase_WidgetMultiSelector.cpp
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_ConstraintMirror.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/Test/TestConstraintMirror.py [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/SketchSolver_Constraint.cpp
src/SketchSolver/SketchSolver_ConstraintGroup.cpp
src/SketchSolver/SketchSolver_ConstraintGroup.h
src/SketcherPrs/SketcherPrs_Tangent.cpp

index 4ad9d0a95edfbbf51a5c45f7ec92992c3af317b6..553d22608a543eeb2383630dd31fbda269e4cd18 100644 (file)
@@ -14,7 +14,8 @@
 #include <memory>
 
 // the only created instance of this plugin
-static InitializationPlugin_Plugin* MY_INITIALIZATIONPLUGIN_INSTANCE = new InitializationPlugin_Plugin();
+static InitializationPlugin_Plugin* MY_INITIALIZATIONPLUGIN_INSTANCE =
+    new InitializationPlugin_Plugin();
 
 InitializationPlugin_Plugin::InitializationPlugin_Plugin()
 {
@@ -27,8 +28,8 @@ void InitializationPlugin_Plugin::processEvent(const std::shared_ptr<Events_Mess
 {
   const Events_ID kDocCreatedEvent = ModelAPI_DocumentCreatedMessage::eventId();
   if (theMessage->eventID() == kDocCreatedEvent) {
-    std::shared_ptr<ModelAPI_DocumentCreatedMessage> aMessage =
-        std::dynamic_pointer_cast<ModelAPI_DocumentCreatedMessage>(theMessage);
+    std::shared_ptr<ModelAPI_DocumentCreatedMessage> aMessage = std::dynamic_pointer_cast<
+        ModelAPI_DocumentCreatedMessage>(theMessage);
     DocumentPtr aDoc = aMessage->document();
     createPoint(aDoc);
     createPlane(aDoc, 1., 0., 0.);
@@ -38,28 +39,29 @@ void InitializationPlugin_Plugin::processEvent(const std::shared_ptr<Events_Mess
     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_CREATED));
   } else if (theMessage.get()) {
     Events_Error::send(
-      std::string("InitializationPlugin_Plugin::processEvent: unhandled message caught: ") + 
-      theMessage->eventID().eventText());
+        std::string("InitializationPlugin_Plugin::processEvent: unhandled message caught: ")
+            + theMessage->eventID().eventText());
   }
 }
 
-void InitializationPlugin_Plugin::createPlane(DocumentPtr theDoc, double theA, double theB, double theC)
+void InitializationPlugin_Plugin::createPlane(DocumentPtr theDoc, double theX, double theY,
+                                              double theZ)
 {
   std::shared_ptr<ModelAPI_Feature> aPlane = theDoc->addFeature("Plane");
   aPlane->string("CreationMethod")->setValue("PlaneByGeneralEquation");
-  aPlane->real("A")->setValue(theA);
-  aPlane->real("B")->setValue(theB);
-  aPlane->real("C")->setValue(theC);
+  aPlane->real("A")->setValue(theX);
+  aPlane->real("B")->setValue(theY);
+  aPlane->real("C")->setValue(theZ);
   aPlane->real("D")->setValue(0.);
 
-  if (theA) {
+  if (theX) {
     aPlane->data()->setName("Y0Z");
-  } else if (theB) {
+  } else if (theY) {
     aPlane->data()->setName("X0Z");
-  } else if (theC) {
+  } else if (theZ) {
     aPlane->data()->setName("X0Y");
   }
-  aPlane->setInHistory(aPlane, false); // don't show automatically created feature in the features history
+  aPlane->setInHistory(aPlane, false);  // don't show automatically created feature in the features history
 }
 
 void InitializationPlugin_Plugin::createPoint(DocumentPtr theDoc)
@@ -69,5 +71,5 @@ void InitializationPlugin_Plugin::createPoint(DocumentPtr theDoc)
   aPoint->real("y")->setValue(0.);
   aPoint->real("z")->setValue(0.);
   aPoint->data()->setName("Origin");
-  aPoint->setInHistory(aPoint, false); // don't show automatically created feature in the features history
+  aPoint->setInHistory(aPoint, false);  // don't show automatically created feature in the features history
 }
index bbd9e4aa02ad6922f40febfb252f08904daf61d7..4ddaf76098bdf0166b7e8c938090e550c7f3db2d 100644 (file)
@@ -1,4 +1,3 @@
-
 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
 
 #ifndef INITIALIZATIONPLUGIN_PLUGIN_H_
 #include <Events_Loop.h>
 
 /**\class InitializationPlugin_Plugin
- * TODO: Add documentation
+ * \ingroup Plugins
+ * This class is represents a plugin.
+ * It's aim is to fulfill the newly created documents with the "origin"
+ * construction point (0,0,0) and base planes (x0y, z0y, x0z)
  */
 class INITIALIZATIONPLUGIN_EXPORT InitializationPlugin_Plugin : public Events_Listener
 {
  public:
+  /// Creates plug-in and registers it in the Event Loop
   InitializationPlugin_Plugin();
-  ~InitializationPlugin_Plugin() {}
+  /// Destructs the plugin
+  virtual ~InitializationPlugin_Plugin() {}
+  /// Process the ModelAPI_DocumentCreatedMessage to fulfill a document
+  /// from the message with origin and planes
   virtual void processEvent(const std::shared_ptr<Events_Message>& theMessage);
 
-  void createPlane(DocumentPtr theDoc, double theA, double theB, double theC);
+ protected:
+  /// Creates a plane by given parameters A, B, C
+  /// \param theDoc - document to contain a "plane" feature
+  /// \param theX - determines if X is 0 or not
+  /// \param theY - determines if Y is 0 or not
+  /// \param theZ - determines if Z is 0 or not
+  void createPlane(DocumentPtr theDoc, double theX, double theY, double theZ);
+  /// Creates the origin point in (0,0,0)
+  /// \param theDoc - document to contain a "point" feature
   void createPoint(DocumentPtr theDoc);
 };
 
index 6ded256f5cf138d69c886d63252e122c213e765c..82cc259187f241baf8d61af17ecd4be53b79251a 100644 (file)
@@ -29,6 +29,9 @@
 #include <Events_Error.h>
 
 #include <TDataStd_Name.hxx>
+#include <TDF_AttributeIterator.hxx>
+#include <TDF_ChildIterator.hxx>
+#include <TDF_RelocationTable.hxx>
 
 #include <string>
 
@@ -304,3 +307,36 @@ void Model_Data::referencesToObjects(
     }
   }
 }
+
+/// makes copy of all attributes on the given label and all sub-labels
+static void copyAttrs(TDF_Label theSource, TDF_Label theDestination) {
+  TDF_AttributeIterator anAttrIter(theSource);
+  for(; anAttrIter.More(); anAttrIter.Next()) {
+    Handle(TDF_Attribute) aTargetAttr;
+    if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
+      // create a new attribute if not yet exists in the destination
+           aTargetAttr = anAttrIter.Value()->NewEmpty();
+      theDestination.AddAttribute(aTargetAttr);
+    }
+    Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable(); // no relocation, empty map
+    anAttrIter.Value()->Paste(aTargetAttr, aRelocTable);
+  }
+  // copy the sub-labels content
+  TDF_ChildIterator aSubLabsIter(theSource);
+  for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
+    copyAttrs(aSubLabsIter.Value(), theDestination.FindChild(aSubLabsIter.Value().Tag()));
+  }
+}
+
+void Model_Data::copyTo(std::shared_ptr<ModelAPI_Data> theTarget)
+{
+  TDF_Label aTargetRoot = std::dynamic_pointer_cast<Model_Data>(theTarget)->label();
+  copyAttrs(myLab, aTargetRoot);
+  // make initialized the initialized attributes
+  std::map<std::string, std::shared_ptr<ModelAPI_Attribute> >::iterator aMyIter = myAttrs.begin();
+  for(; aMyIter != myAttrs.end(); aMyIter++) {
+    if (aMyIter->second->isInitialized()) {
+      theTarget->attribute(aMyIter->first)->setInitialized();
+    }
+  }
+}
index 4695446ce9b29eadd7e256b30c837d3f462338b3..5a2f6296e1a385745534e42fd2c56312aa4be27a 100644 (file)
@@ -176,6 +176,9 @@ class Model_Data : public ModelAPI_Data
   MODEL_EXPORT virtual void referencesToObjects(
     std::list<std::pair<std::string, std::list<ObjectPtr> > >& theRefs);
 
+  /// Copies all atributes content into theTarget data
+  MODEL_EXPORT virtual void copyTo(std::shared_ptr<ModelAPI_Data> theTarget);
+
 private:
   /// removes all information about back references
   void eraseBackReferences();
index f9abb5367e33759dffbd10b0d77c896459339f91..3a922d5061e98579362ae38dc9e4aca4a221ef24 100644 (file)
@@ -136,7 +136,11 @@ class MODELAPI_EXPORT ModelAPI_Data
   /// returns all references by attributes of this data
   /// \param theRefs returned list of pairs: id of referenced attribute and list of referenced objects
   virtual void referencesToObjects(
-    std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > >& theRefs) = 0;
+    std::list<std::pair<std::string, std::list<std::shared_ptr<ModelAPI_Object> > > >& theRefs) =0;
+
+  /// Copies all atributes content into theTarget data
+  virtual void copyTo(std::shared_ptr<ModelAPI_Data> theTarget) = 0;
+
  protected:
   /// Objects are created for features automatically
   ModelAPI_Data();
index 96395a997f9407c668521c29ba3624a79c7dfa43..20d2530bb1c9ddf12d3bf35642b0acbf9cc18998 100644 (file)
@@ -150,15 +150,16 @@ class ModelAPI_DocumentCreatedMessage : public Events_Message
   MODELAPI_EXPORT ModelAPI_DocumentCreatedMessage(const Events_ID theID, const void* theSender = 0);
   /// The virtual destructor
   MODELAPI_EXPORT virtual ~ModelAPI_DocumentCreatedMessage();
-
+  /// Static. Returns EventID of the message.
   MODELAPI_EXPORT static Events_ID eventId()
   {
     static const char * MY_DOCUMENT_CREATED_EVENT_ID("DocumentCreated");
     return Events_Loop::eventByName(MY_DOCUMENT_CREATED_EVENT_ID);
   }
 
-
+  /// Returns a document stored in the message
   MODELAPI_EXPORT DocumentPtr document() const;
+  /// Sets a document to the message
   MODELAPI_EXPORT void setDocument(DocumentPtr theDocument);
 };
 
index 29e9dcd1457f55a36fd898655325ea1206e52dc8..63be634d3996e1ef547fb3bdfec3ab58b706e92a 100644 (file)
@@ -16,31 +16,43 @@ class QLayout;
 class QWidget;
 
 /*!
- * Represent a property panel's list of ModuleBase_ModelWidgets.
+ * Represent a property panel's list of ModuleBase_ModelWidgets
+ * or other pages widgets derived from ModuleBase_PageBase.
  */
 class MODULEBASE_EXPORT ModuleBase_PageBase
 {
  public:
+  /// Base constructor.
   ModuleBase_PageBase();
+  /// Base virtual destructor.
   virtual ~ModuleBase_PageBase();
+  /// Cast the page to regular QWidget
   QWidget* pageWidget();
-
+  /// Adds the given ModuleBase_ModelWidget to the page
   void addModelWidget(ModuleBase_ModelWidget* theWidget);
+  /// Adds the given ModuleBase_PageBase to the page
   void addPageWidget(ModuleBase_PageBase* theWidget);
-
+  /// Removes all items from page's layout
   void clearPage();
+  /// Passes focus from page to the first ModuleBase_ModelWidget contained on the page
   bool takeFocus();
+  /// Returns list of ModuleBase_ModelWidgets contained on the page
   QList<ModuleBase_ModelWidget*> modelWidgets();
+  /// Aligns top all widgets on page
   void alignToTop();
 
  protected:
+  /// Pure Virtual. Allows to derived class to lay out the widget properly;
   virtual void placeModelWidget(ModuleBase_ModelWidget* theWidget) = 0;
+  /// Pure Virtual. Allows to derived class to lay out the page properly;
   virtual void placePageWidget(ModuleBase_PageBase* theWidget) = 0;
+  /// Pure Virtual. Returns layout of the page.
   virtual QLayout* pageLayout() = 0;
+  /// Pure Virtual. Allows to derived class to insert page stretch properly.
   virtual void addPageStretch() = 0;
 
  private:
-  QList<ModuleBase_ModelWidget*> myWidgetList;
+  QList<ModuleBase_ModelWidget*> myWidgetList; ///< list of widgets contained on the page
 
 };
 
index fd10f001b23ec99f5185488d7c6e7c0790d78f67..ee28287ed1bac16b19cdc2a91f86fbb3cd8caa43 100644 (file)
@@ -23,18 +23,25 @@ class QGridLayout;
  */
 class MODULEBASE_EXPORT ModuleBase_PageGroupBox : public QGroupBox, public ModuleBase_PageBase
 {
+  Q_OBJECT
  public:
+  /// Constructs a page that looks like a QGroupBox
   explicit ModuleBase_PageGroupBox(QWidget* theParent = 0);
+  /// Destructs the page
   virtual ~ModuleBase_PageGroupBox();
 
  protected:
+  /// Adds the given widget to page's layout
   virtual void placeModelWidget(ModuleBase_ModelWidget* theWidget);
+  /// Adds the given page to page's layout
   virtual void placePageWidget(ModuleBase_PageBase* theWidget);
+  /// Returns page's layout (QGridLayout)
   virtual QLayout* pageLayout();
+  /// Adds a stretch to page's layout
   virtual void addPageStretch();
 
  private:
-  QGridLayout* myMainLayout;
+  QGridLayout* myMainLayout; ///< page's layout
 };
 
 #endif /* MODULEBASE_PAGEGROUPBOX_H_ */
index eb21a6daac9dab25ecc7ce56a3682db78bdd714a..33d552d5fcb318a7963c951357b8428ec0c669a5 100644 (file)
@@ -22,18 +22,25 @@ class QGridLayout;
  */
 class MODULEBASE_EXPORT ModuleBase_PageWidget : public QFrame, public ModuleBase_PageBase
 {
+  Q_OBJECT
  public:
+  /// Constructs a page that looks like a QFrame
   explicit ModuleBase_PageWidget(QWidget* theParent = 0);
+  /// Destructs the page
   virtual ~ModuleBase_PageWidget();
 
  protected:
+  /// Adds the given widget to page's layout
   virtual void placeModelWidget(ModuleBase_ModelWidget* theWidget);
+  /// Adds the given page to page's layout
   virtual void placePageWidget(ModuleBase_PageBase* theWidget);
+  /// Returns page's layout (QGridLayout)
   virtual QLayout* pageLayout();
+  /// Adds a stretch to page's layout
   virtual void addPageStretch();
 
  private:
-  QGridLayout* myMainLayout;
+  QGridLayout* myMainLayout; ///< page's layout
 };
 
 #endif /* MODULEBASE_PAGEWIDGET_H_ */
index edf9f03ade3c5062e41dbd527c7a2772dbc1045c..22145d36f37be5a36554711d88753fe57919806a 100644 (file)
@@ -214,7 +214,7 @@ void ModuleBase_WidgetMultiSelector::onSelectionChanged()
   for (aIt = aOwnersList.cbegin(); aIt != aOwnersList.cend(); aShpIt.Next(), aIt++) {
     ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(*aIt);
     // this case should be moved to PartSet module after redesign this class
-    if (aShpIt.Value().ShapeType() == TopAbs_COMPOUND) {
+    /*if (aShpIt.Value().ShapeType() == TopAbs_COMPOUND) {
       int aValue = 0;
       AIS_ListOfInteractive aList;
       aSelection->selectedAISObjects(aList);
@@ -237,7 +237,8 @@ void ModuleBase_WidgetMultiSelector::onSelectionChanged()
         }
       }
     }
-    else {
+    else*/
+    {
       if (myFeature) {
         // We can not select a result of our feature
         const std::list<ResultPtr>& aResList = myFeature->results();
@@ -255,7 +256,12 @@ void ModuleBase_WidgetMultiSelector::onSelectionChanged()
       aShape = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape());
       aShape->setImpl(new TopoDS_Shape(aShpIt.Value()));
 
-      mySelection.append(GeomSelection(aResult, aShape));
+      if (aShape->isEqual(aResult->shape())) {
+        //aShape = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape());
+        mySelection.append(GeomSelection(aResult, NULL));//aShape));
+      }
+      else
+        mySelection.append(GeomSelection(aResult, aShape));
     }
   }
   //updateSelectionList();
index e2fc7682907a66d296778b08b05c3209a0a6fe29..1a70246b266ce1014a02ee877d7fead52264952d 100644 (file)
@@ -26,6 +26,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_ConstraintVertical.h
     SketchPlugin_ConstraintEqual.h
     SketchPlugin_ConstraintTangent.h
+    SketchPlugin_ConstraintMirror.h
     SketchPlugin_ShapeValidator.h
     SketchPlugin_Validators.h
     SketchPlugin_ResultValidators.h 
@@ -52,6 +53,7 @@ SET(PROJECT_SOURCES
     SketchPlugin_ConstraintVertical.cpp
     SketchPlugin_ConstraintEqual.cpp
     SketchPlugin_ConstraintTangent.cpp
+    SketchPlugin_ConstraintMirror.cpp
     SketchPlugin_ShapeValidator.cpp
     SketchPlugin_Validators.cpp
     SketchPlugin_ResultValidators.cpp
@@ -101,5 +103,6 @@ ADD_UNIT_TESTS(TestSketchPointLine.py
                TestConstraintVertical.py
                TestConstraintEqual.py
                TestConstraintTangent.py
+               TestConstraintMirror.py
                TestHighload.py
                TestSnowflake.py)
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp b/src/SketchPlugin/SketchPlugin_ConstraintMirror.cpp
new file mode 100644 (file)
index 0000000..8479e10
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File:    SketchPlugin_ConstraintMirror.cpp
+// Created: 17 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#include "SketchPlugin_ConstraintMirror.h"
+
+#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_Data.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_AttributeRefList.h>
+#include <ModelAPI_Session.h>
+
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <SketcherPrs_Factory.h>
+
+#include <Config_PropManager.h>
+
+SketchPlugin_ConstraintMirror::SketchPlugin_ConstraintMirror()
+{
+}
+
+void SketchPlugin_ConstraintMirror::initAttributes()
+{
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::type());
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefList::type());
+  data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeRefList::type());
+}
+
+void SketchPlugin_ConstraintMirror::execute()
+{
+  // Objects to be mirrored will be created here
+  std::shared_ptr<ModelAPI_Data> aData = data();
+  AttributeRefListPtr aRefListOfShapes = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+      aData->attribute(SketchPlugin_Constraint::ENTITY_B()));
+  if (!aRefListOfShapes->isInitialized())
+    return ;
+
+  AttributeRefListPtr aRefListOfMirrored = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+      aData->attribute(SketchPlugin_Constraint::ENTITY_C()));
+  // Check consistency of initial list and mirrored list
+  std::list<ObjectPtr> anInitialList =  aRefListOfShapes->list();
+  std::list<ObjectPtr> aMirroredList =  aRefListOfMirrored->list();
+  std::list<ObjectPtr>::iterator anInitIter = anInitialList.begin();
+  std::list<ObjectPtr>::iterator aMirrorIter = aMirroredList.begin();
+  int indFirstWrong = 0; // index of element starts difference in the lists
+  std::set<int> anInvalidInd; // list of indices of removed features
+  std::shared_ptr<SketchPlugin_Feature> aFeatureIn, aFeatureOut;
+  for ( ; anInitIter != anInitialList.end(); anInitIter++, indFirstWrong++) {
+    // Add features and store indices of objects to remove
+    aFeatureIn = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anInitIter);
+    aFeatureOut = aMirrorIter != aMirroredList.end() ? 
+        std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirrorIter) :
+        std::shared_ptr<SketchPlugin_Feature>();
+    if (!aFeatureIn) {
+      if (aFeatureOut)
+        break; // the lists are inconsistent
+      continue;
+    }
+    if (!aFeatureOut) {
+      if (aMirrorIter != aMirroredList.end())
+        break; // the lists are inconsistent
+      // There is no mirrored object yet, create it
+      FeaturePtr aNewFeature = sketch()->addFeature(aFeatureIn->getKind());
+      aFeatureIn->data()->copyTo(aNewFeature->data());
+      aRefListOfMirrored->append(aNewFeature);
+      continue;
+    }
+    if (aFeatureIn->getKind() != aFeatureOut->getKind())
+      break; // the lists are inconsistent
+    if (!aFeatureIn->data()->isValid()) {
+      // initial feature was removed, delete it from lists
+      anInvalidInd.insert(indFirstWrong);
+    }
+    aMirrorIter++;
+  }
+  // Remove from the list objects already deleted before
+  std::set<int>::reverse_iterator anIt = anInvalidInd.rbegin();
+  for ( ; anIt != anInvalidInd.rend(); anIt++) {
+    if (*anIt < indFirstWrong) indFirstWrong--;
+    aRefListOfShapes->remove(aRefListOfShapes->object(*anIt));
+    aRefListOfMirrored->remove(aRefListOfMirrored->object(*anIt));
+  }
+  // If the lists inconsistent, remove all objects from mirrored list starting from indFirstWrong
+  if (anInitIter != anInitialList.end()) {
+    while (aRefListOfMirrored->size() > indFirstWrong)
+      aRefListOfMirrored->remove(aRefListOfMirrored->object(indFirstWrong));
+    // Create mirrored features instead of removed
+    anInitialList =  aRefListOfShapes->list();
+    anInitIter = anInitialList.begin();
+    for (int i = 0; i < indFirstWrong; i++) anInitIter++;
+    for ( ; anInitIter != anInitialList.end(); anInitIter++) {
+      aFeatureIn = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anInitIter);
+      FeaturePtr aNewFeature = aFeatureIn->document()->addFeature(aFeatureIn->getKind());
+      aRefListOfMirrored->append(aNewFeature);
+    }
+  }
+}
+
+AISObjectPtr SketchPlugin_ConstraintMirror::getAISObject(AISObjectPtr thePrevious)
+{
+  if (!sketch())
+    return thePrevious;
+
+  AISObjectPtr anAIS = thePrevious;
+  /// TODO: Equal constraint presentation should be put here
+  return anAIS;
+}
+
+
diff --git a/src/SketchPlugin/SketchPlugin_ConstraintMirror.h b/src/SketchPlugin/SketchPlugin_ConstraintMirror.h
new file mode 100644 (file)
index 0000000..841f11a
--- /dev/null
@@ -0,0 +1,54 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D -->
+
+// File:    SketchPlugin_ConstraintMirror.h
+// Created: 17 Mar 2015
+// Author:  Artem ZHIDKOV
+
+#ifndef SketchPlugin_ConstraintMirror_H_
+#define SketchPlugin_ConstraintMirror_H_
+
+#include "SketchPlugin.h"
+#include <SketchPlugin_Sketch.h>
+#include "SketchPlugin_ConstraintBase.h"
+
+/** \class SketchPlugin_ConstraintMirror
+ *  \ingroup Plugins
+ *  \brief Feature for creation of a new constraint mirroring a list of objects regarding to a given line
+ *
+ *  This constraint has two attributes:
+ *  SketchPlugin_Constraint::ENTITY_A() for mirror line and
+ *  SketchPlugin_Constraint::ENTITY_B() for the list of objects
+ *
+ *  Also the constraint has attribute SketchPlugin_Constraint::ENTITY_C()
+ *  which contains list of mirrored objects
+ */
+class SketchPlugin_ConstraintMirror : public SketchPlugin_ConstraintBase
+{
+ public:
+  /// Mirror constraint kind
+  inline static const std::string& ID()
+  {
+    static const std::string MY_CONSTRAINT_MIRROR_ID("SketchConstraintMirror");
+    return MY_CONSTRAINT_MIRROR_ID;
+  }
+  /// \brief Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_ConstraintMirror::ID();
+    return MY_KIND;
+  }
+
+  /// \brief Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// \brief Request for initialization of data model of the feature: adding all attributes
+  SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Returns the AIS preview
+  SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// \brief Use plugin manager for features creation
+  SketchPlugin_ConstraintMirror();
+};
+
+#endif
index fd9b04f8ac6331ea67e0bf9f130ae1f6c81d575a..fbf1235ce2e6e07616757b2d64f045a6614a0cf0 100644 (file)
@@ -11,6 +11,7 @@
 #include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_ConstraintHorizontal.h>
 #include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMirror.h>
 #include <SketchPlugin_ConstraintParallel.h>
 #include <SketchPlugin_ConstraintPerpendicular.h>
 #include <SketchPlugin_ConstraintRadius.h>
@@ -121,6 +122,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(string theFeatureID)
     return FeaturePtr(new SketchPlugin_ConstraintEqual);
   } else if (theFeatureID == SketchPlugin_ConstraintTangent::ID()) {
     return FeaturePtr(new SketchPlugin_ConstraintTangent);
+  } else if (theFeatureID == SketchPlugin_ConstraintMirror::ID()) {
+    return FeaturePtr(new SketchPlugin_ConstraintMirror);
   }
   // feature of such kind is not found
   return FeaturePtr();
@@ -169,6 +172,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_ConstraintVertical::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintEqual::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_ConstraintTangent::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_ConstraintMirror::ID(), aHasSketchPlane);
     }
   }
   return aMsg;
diff --git a/src/SketchPlugin/Test/TestConstraintMirror.py b/src/SketchPlugin/Test/TestConstraintMirror.py
new file mode 100644 (file)
index 0000000..3c3c2d0
--- /dev/null
@@ -0,0 +1,158 @@
+"""
+    TestConstraintMirror.py
+    Unit test of SketchPlugin_ConstraintMirror class
+        
+    SketchPlugin_ConstraintMirror
+        static const std::string MY_CONSTRAINT_MIRROR_ID("SketchConstraintMirror");
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_A(), ModelAPI_AttributeRefAttr::type());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_B(), ModelAPI_AttributeRefListAttr::type());
+        data()->addAttribute(SketchPlugin_Constraint::ENTITY_C(), ModelAPI_AttributeRefListAttr::type());
+
+"""
+from GeomDataAPI import *
+from ModelAPI import *
+import math
+#=========================================================================
+# Initialization of the test
+#=========================================================================
+
+__updated__ = "2015-03-17"
+
+aSession = ModelAPI_Session.get()
+aDocument = aSession.moduleDocument()
+#=========================================================================
+# Creation of a sketch
+#=========================================================================
+aSession.startOperation()
+aSketchCommonFeature = aDocument.addFeature("Sketch")
+aSketchFeature = modelAPI_CompositeFeature(aSketchCommonFeature)
+origin = geomDataAPI_Point(aSketchFeature.attribute("Origin"))
+origin.setValue(0, 0, 0)
+dirx = geomDataAPI_Dir(aSketchFeature.attribute("DirX"))
+dirx.setValue(1, 0, 0)
+diry = geomDataAPI_Dir(aSketchFeature.attribute("DirY"))
+diry.setValue(0, 1, 0)
+norm = geomDataAPI_Dir(aSketchFeature.attribute("Norm"))
+norm.setValue(0, 0, 1)
+aSession.finishOperation()
+#=========================================================================
+# Creation of an arc and two lines
+#=========================================================================
+# Arc
+aSession.startOperation()
+aSketchArc1 = aSketchFeature.addFeature("SketchArc")
+anArcCentr = geomDataAPI_Point2D(aSketchArc1.attribute("ArcCenter"))
+anArcCentr.setValue(10., 10.)
+anArcStartPoint = geomDataAPI_Point2D(aSketchArc1.attribute("ArcStartPoint"))
+anArcStartPoint.setValue(0., 50.)
+anArcEndPoint = geomDataAPI_Point2D(aSketchArc1.attribute("ArcEndPoint"))
+anArcEndPoint.setValue(50., 0.)
+aSession.finishOperation()
+# Line 1
+aSession.startOperation()
+aSketchLine1 = aSketchFeature.addFeature("SketchLine")
+aLine1StartPoint = geomDataAPI_Point2D(aSketchLine1.attribute("StartPoint"))
+aLine1EndPoint = geomDataAPI_Point2D(aSketchLine1.attribute("EndPoint"))
+aLine1StartPoint.setValue(0., 50.)
+aLine1EndPoint.setValue(0., 100.)
+aSession.finishOperation()
+# Line 2
+aSession.startOperation()
+aSketchLine2 = aSketchFeature.addFeature("SketchLine")
+aLine2StartPoint = geomDataAPI_Point2D(aSketchLine2.attribute("StartPoint"))
+aLine2EndPoint = geomDataAPI_Point2D(aSketchLine2.attribute("EndPoint"))
+aLine2StartPoint.setValue(50., 0.)
+aLine2EndPoint.setValue(100., 0.)
+aSession.finishOperation()
+#=========================================================================
+# Link arc points and lines points by the coincidence constraint
+#=========================================================================
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintCoincidence")
+reflistA = aConstraint.refattr("ConstraintEntityA")
+reflistB = aConstraint.refattr("ConstraintEntityB")
+reflistA.setAttr(anArcStartPoint)
+reflistB.setAttr(aLine1StartPoint)
+aConstraint.execute()
+aSession.finishOperation()
+aSession.startOperation()
+aConstraint = aSketchFeature.addFeature("SketchConstraintCoincidence")
+reflistA = aConstraint.refattr("ConstraintEntityA")
+reflistB = aConstraint.refattr("ConstraintEntityB")
+reflistA.setAttr(anArcEndPoint)
+reflistB.setAttr(aLine2StartPoint)
+aConstraint.execute()
+aSession.finishOperation()
+#=========================================================================
+# Add tangency constraint and check correctness
+#=========================================================================
+aSession.startOperation()
+aTangency = aSketchFeature.addFeature("SketchConstraintTangent")
+aRefObjectA = aTangency.refattr("ConstraintEntityA")
+aRefObjectB = aTangency.refattr("ConstraintEntityB")
+anObjectA = modelAPI_ResultConstruction(aSketchArc1.lastResult())
+anObjectB = modelAPI_ResultConstruction(aSketchLine1.firstResult())
+assert (anObjectA is not None)
+assert (anObjectB is not None)
+aRefObjectA.setObject(anObjectA)
+aRefObjectB.setObject(anObjectB)
+aTangency.execute()
+aSession.finishOperation()
+#=========================================================================
+# Create mirror line
+#=========================================================================
+aSession.startOperation()
+aMirrorLine = aSketchFeature.addFeature("SketchLine")
+aLineStartPoint = geomDataAPI_Point2D(aMirrorLine.attribute("StartPoint"))
+aLineEndPoint = geomDataAPI_Point2D(aMirrorLine.attribute("EndPoint"))
+aLineStartPoint.setValue(100., 0.)
+aLineEndPoint.setValue(100., 100.)
+aSession.finishOperation()
+#=========================================================================
+# Make mirror for objects created above
+#=========================================================================
+aSession.startOperation()
+aMirror = aSketchFeature.addFeature("SketchConstraintMirror")
+aRefObjectA = aMirror.refattr("ConstraintEntityA")
+aRefObjectA.setObject(modelAPI_ResultConstruction(aMirrorLine.firstResult()))
+aRefListB = aMirror.reflist("ConstraintEntityB")
+aRefListB.append(aSketchArc1)
+aRefListB.append(aSketchLine1)
+aRefListB.append(aSketchLine2)
+aMirror.execute()
+aSession.finishOperation()
+#=========================================================================
+# Verify the simmetricity of all mirrored objects
+#=========================================================================
+aRefListC = aMirror.reflist("ConstraintEntityC")
+aListSize = aRefListB.size()
+aLineDirX = aLineEndPoint.x() - aLineStartPoint.x()
+aLineDirY = aLineEndPoint.y() - aLineStartPoint.y()
+
+for ind in range(0, aListSize):
+  aFeatureB = modelAPI_Feature(aRefListB.object(ind))
+  aFeatureC = modelAPI_Feature(aRefListC.object(ind))
+  assert(aFeatureB is not None)
+  assert(aFeatureC is not None)
+  assert(aFeatureB.getKind() == aFeatureC.getKind())
+  anAttributes = {}
+  print aFeatureB.getKind()
+  if (aFeatureB.getKind() == "SketchLine"):
+    anAttributes = {'StartPoint':'StartPoint', 'EndPoint':'EndPoint'}
+  elif (aFeatureB.getKind() == "SketchArc"):
+    anAttributes = {'ArcCenter':'ArcCenter', 'ArcStartPoint':'ArcEndPoint', 'ArcEndPoint':'ArcStartPoint'}
+
+  for key in anAttributes:
+    aPointB = geomDataAPI_Point2D(aFeatureB.attribute(key))
+    aPointC = geomDataAPI_Point2D(aFeatureC.attribute(anAttributes[key]))
+    aDirX = aPointC.x() - aPointB.x()
+    aDirY = aPointC.y() - aPointB.y()
+    aDot = aLineDirX * aDirX + aLineDirY * aDirY
+    assert(math.fabs(aDot) < 1.e-10)
+    aDirX = aLineEndPoint.x() - 0.5 * (aPointB.x() + aPointC.x())
+    aDirY = aLineEndPoint.y() - 0.5 * (aPointB.y() + aPointC.y())
+    aCross = aLineDirX * aDirY - aLineDirY * aDirX
+    assert(math.fabs(aCross) < 1.e-10)
+#=========================================================================
+# End of test
+#=========================================================================
index 3bbfbfead5ede7681d3377d7523da86fe28b7454..b4a7ab35b24d03bc609a1e3a0ea7581719d2b886 100644 (file)
             label="Last object" tooltip="Select line or arc" shape_types="edge">
         </sketch_constraint_shape_selector>
       </feature>
+    <!--  SketchConstraintMirror  -->
+      <feature
+        id="SketchConstraintMirror"
+        title="Mirror"
+        tooltip="Create constraint mirroring group of objects"
+        internal="1" />
     </group>
   </workbench>
 </plugin>
index e4af2a0643970b1518b35cd344566ccaffdce20a..aed82cec5b1f2c16143eae40c737440f37c9322c 100644 (file)
@@ -16,6 +16,7 @@
 #include <SketchPlugin_ConstraintEqual.h>
 #include <SketchPlugin_ConstraintHorizontal.h>
 #include <SketchPlugin_ConstraintLength.h>
+#include <SketchPlugin_ConstraintMirror.h>
 #include <SketchPlugin_ConstraintParallel.h>
 #include <SketchPlugin_ConstraintPerpendicular.h>
 #include <SketchPlugin_ConstraintRadius.h>
@@ -24,6 +25,7 @@
 #include <SketchPlugin_ConstraintVertical.h>
 
 #include <ModelAPI_AttributeRefAttr.h>
+#include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_Data.h>
 #include <ModelAPI_Document.h>
 #include <ModelAPI_Object.h>
@@ -217,8 +219,7 @@ const int& SketchSolver_Constraint::getType(
     return getType();
   }
 
-  if (aConstraintKind.compare(SketchPlugin_ConstraintEqual::ID()) == 0)
-  {
+  if (aConstraintKind.compare(SketchPlugin_ConstraintEqual::ID()) == 0) {
     static const int aConstrType[3] = {
         SLVS_C_EQUAL_RADIUS,
         SLVS_C_EQUAL_LINE_ARC_LEN,
@@ -242,8 +243,7 @@ const int& SketchSolver_Constraint::getType(
     return getType();
   }
 
-  if (aConstraintKind.compare(SketchPlugin_ConstraintTangent::ID()) == 0)
-  {
+  if (aConstraintKind.compare(SketchPlugin_ConstraintTangent::ID()) == 0) {
     static const int anArcPosDefault = 2;
     static const int aLinePosDefault = 3;
     int anArcPos = anArcPosDefault; // arc in tangency constraint should be placed before line
@@ -262,6 +262,30 @@ const int& SketchSolver_Constraint::getType(
     return getType();
   }
 
+  if (aConstraintKind.compare(SketchPlugin_ConstraintMirror::ID()) == 0) {
+    int aNbAttrs = 0;
+    bool hasMirrorLine = false;
+    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++) {
+      AttributeRefListPtr anAttrRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+          aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr)));
+      if (anAttrRefList) {
+        aNbAttrs++;
+        myAttributesList[aNbAttrs] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+      }
+      else {
+        std::shared_ptr<ModelAPI_Attribute> anAttr = 
+            aConstrData->attribute(SketchPlugin_Constraint::ATTRIBUTE(indAttr));
+        if (typeOfAttribute(anAttr) == LINE) {
+          hasMirrorLine = !hasMirrorLine;
+          myAttributesList[0] = SketchPlugin_Constraint::ATTRIBUTE(indAttr);
+        }
+      }
+    }
+    if (aNbAttrs == 2 && hasMirrorLine)
+      myType = SLVS_C_SYMMETRIC_LINE;
+    return getType();
+  }
+
   /// \todo Implement other kind of constraints
 
   return getType();
index 61299f8a7c0bf55ec19a89dace873b947f581a5a..4340f7018f0a6bba42d3ceb987375827b86ba245 100644 (file)
@@ -24,6 +24,7 @@
 #include <SketchPlugin_Constraint.h>
 #include <SketchPlugin_ConstraintLength.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
+#include <SketchPlugin_ConstraintMirror.h>
 #include <SketchPlugin_ConstraintRigid.h>
 
 #include <SketchPlugin_Arc.h>
@@ -155,7 +156,19 @@ bool SketchSolver_ConstraintGroup::isInteract(
   std::list<std::shared_ptr<ModelAPI_Attribute>>::const_iterator
       anAttrIter = anAttrList.begin();
   for ( ; anAttrIter != anAttrList.end(); anAttrIter++) {
-    std::shared_ptr<ModelAPI_AttributeRefAttr> aCAttrRef =
+    AttributeRefListPtr aCAttrRefList = 
+        std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(*anAttrIter);
+    if (aCAttrRefList) {
+      std::list<ObjectPtr> anObjList = aCAttrRefList->list();
+      std::list<ObjectPtr>::iterator anIt = anObjList.begin();
+      for ( ; anIt != anObjList.end(); anIt++) {
+        FeaturePtr aFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(*anIt);
+        if (aFeature && myEntityFeatMap.find(aFeature) != myEntityFeatMap.end())
+          return true;
+      }
+      continue;
+    }
+    AttributeRefAttrPtr aCAttrRef =
         std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
     if (!aCAttrRef || !aCAttrRef->isObject()) {
       std::shared_ptr<ModelAPI_Attribute> anAttr = 
@@ -232,8 +245,12 @@ bool SketchSolver_ConstraintGroup::changeConstraint(
   if (myWorkplane.h == SLVS_E_UNKNOWN)
     return false;
 
-  if (theConstraint && theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
-    return changeRigidConstraint(theConstraint);
+  if (theConstraint) {
+    if (theConstraint->getKind() == SketchPlugin_ConstraintRigid::ID())
+      return changeRigidConstraint(theConstraint);
+    if (theConstraint->getKind() == SketchPlugin_ConstraintMirror::ID())
+      return changeMirrorConstraint(theConstraint);
+  }
 
   // Search this constraint in the current group to update it
   ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
@@ -582,6 +599,146 @@ bool SketchSolver_ConstraintGroup::changeRigidConstraint(
   return true;
 }
 
+// ============================================================================
+//  Function: changeMirrorConstraint
+//  Class:    SketchSolver_ConstraintGroup
+//  Purpose:  create/update the "Mirror" constraint in the group
+// ============================================================================
+bool SketchSolver_ConstraintGroup::changeMirrorConstraint(
+    std::shared_ptr<SketchPlugin_Constraint> theConstraint)
+{
+  DataPtr aConstrData = theConstraint->data();
+
+  // Search this constraint in the current group to update it
+  ConstraintMap::const_iterator aConstrMapIter = myConstraintMap.find(theConstraint);
+  std::vector<Slvs_Constraint>::iterator aConstrIter;
+  if (aConstrMapIter != myConstraintMap.end()) {
+    int aConstrPos = Search(aConstrMapIter->second.front(), myConstraints);
+    aConstrIter = myConstraints.begin() + aConstrPos;
+  }
+
+  // Get constraint type and verify the constraint parameters are correct
+  SketchSolver_Constraint aConstraint(theConstraint);
+  int aConstrType = aConstraint.getType();
+  if (aConstrType == SLVS_C_UNKNOWN
+      || (aConstrMapIter != myConstraintMap.end() && aConstrIter->type != aConstrType))
+    return false;
+  const std::vector<std::string>& aConstraintAttributes = aConstraint.getAttributes();
+
+  Slvs_hEntity aMirrorLineEnt = SLVS_E_UNKNOWN;
+  AttributeRefAttrPtr aConstrAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+      aConstrData->attribute(aConstraintAttributes[0]));
+  if (!aConstrAttr)
+    return false;
+
+  // Convert the object of the attribute to the feature
+  FeaturePtr aMirrorLineFeat;
+  if (aConstrAttr->isObject() && aConstrAttr->object()) {
+    ResultConstructionPtr aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
+        aConstrAttr->object());
+    if (!aRC)
+      return false;
+    std::shared_ptr<ModelAPI_Document> aDoc = aRC->document();
+    aMirrorLineFeat = aDoc->feature(aRC);
+  }
+  aMirrorLineEnt = aConstrAttr->isObject() ?
+      changeEntityFeature(aMirrorLineFeat) : changeEntity(aConstrAttr->attr());
+
+  if (aConstrMapIter == myConstraintMap.end()) { // Add new constraint
+    // Append symmetric constraint for each point of mirroring features
+    AttributeRefListPtr aBaseRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+        aConstrData->attribute(aConstraintAttributes[1]));
+    AttributeRefListPtr aMirroredRefList = std::dynamic_pointer_cast<ModelAPI_AttributeRefList>(
+        aConstrData->attribute(aConstraintAttributes[2]));
+    if (!aBaseRefList || !aMirroredRefList)
+      return false;
+
+    std::list<ObjectPtr> aBaseList = aBaseRefList->list();
+    std::list<ObjectPtr> aMirroredList = aMirroredRefList->list();
+    if (aBaseList.size() != aMirroredList.size())
+      return false;
+
+    myConstraintMap[theConstraint] = std::vector<Slvs_hEntity>();
+
+    FeaturePtr aBaseFeature, aMirrorFeature;
+    ResultConstructionPtr aRC;
+    std::list<ObjectPtr>::iterator aBaseIter = aBaseList.begin();
+    std::list<ObjectPtr>::iterator aMirIter = aMirroredList.begin();
+    for ( ; aBaseIter != aBaseList.end(); aBaseIter++, aMirIter++) {
+      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aBaseIter);
+      aBaseFeature = aRC ? aRC->document()->feature(aRC) :
+          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aBaseIter);
+      aRC = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aMirIter);
+      aMirrorFeature = aRC ? aRC->document()->feature(aRC) :
+          std::dynamic_pointer_cast<SketchPlugin_Feature>(*aMirIter);
+
+      if (!aBaseFeature || !aMirrorFeature || 
+          aBaseFeature->getKind() != aMirrorFeature->getKind())
+        return false;
+      Slvs_hEntity aBaseEnt = changeEntityFeature(aBaseFeature);
+      Slvs_hEntity aMirrorEnt = changeEntityFeature(aMirrorFeature);
+
+      if (aBaseFeature->getKind() == SketchPlugin_Point::ID()) {
+        Slvs_Constraint aConstraint = Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType,
+            myWorkplane.h, 0.0, aBaseEnt, aMirrorEnt, aMirrorLineEnt, SLVS_E_UNKNOWN);
+        myConstraints.push_back(aConstraint);
+        myConstraintMap[theConstraint].push_back(aConstraint.h);
+      } else {
+        int aBasePos = Search(aBaseEnt, myEntities);
+        int aMirrorPos = Search(aMirrorEnt, myEntities);
+        if (aBaseFeature->getKind() == SketchPlugin_Line::ID()) {
+          for (int ind = 0; ind < 2; ind++) {
+            Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+                ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+                myEntities[aBasePos].point[ind], myEntities[aMirrorPos].point[ind],
+                aMirrorLineEnt, SLVS_E_UNKNOWN);
+            myConstraints.push_back(aConstraint);
+            myConstraintMap[theConstraint].push_back(aConstraint.h);
+          }
+        } else if (aBaseFeature->getKind() == SketchPlugin_Circle::ID()) {
+          Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+              ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+              myEntities[aBasePos].point[0], myEntities[aMirrorPos].point[0],
+              aMirrorLineEnt, SLVS_E_UNKNOWN);
+          myConstraints.push_back(aConstraint);
+          myConstraintMap[theConstraint].push_back(aConstraint.h);
+          // Additional constraint for equal radii
+          Slvs_Constraint anEqRadConstr = Slvs_MakeConstraint(
+              ++myConstrMaxID, myID, SLVS_C_EQUAL_RADIUS, myWorkplane.h, 0.0,
+              SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, aBaseEnt, aMirrorEnt);
+          myConstraints.push_back(anEqRadConstr);
+          myConstraintMap[theConstraint].push_back(anEqRadConstr.h);
+        } else if (aBaseFeature->getKind() == SketchPlugin_Arc::ID()) {
+          int aBaseArcInd[3] = {0, 1, 2}; // indices of points of arc, center corresponds center, first point corresponds last point
+          int aMirrorArcInd[3] = {0, 2, 1};
+          for (int ind = 0; ind < 3; ind++) {
+            Slvs_Constraint aConstraint = Slvs_MakeConstraint(
+                ++myConstrMaxID, myID, aConstrType, myWorkplane.h, 0.0,
+                myEntities[aBasePos].point[aBaseArcInd[ind]], myEntities[aMirrorPos].point[aMirrorArcInd[ind]],
+                aMirrorLineEnt, SLVS_E_UNKNOWN);
+            myConstraints.push_back(aConstraint);
+            myConstraintMap[theConstraint].push_back(aConstraint.h);
+          }
+        }
+      }
+    }
+
+    // Set the mirror line unchanged during constraint recalculation
+    int aMirrorLinePos = Search(aMirrorLineEnt, myEntities);
+    Slvs_Constraint aRigidStart = Slvs_MakeConstraint(
+        ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
+        myEntities[aMirrorLinePos].point[0], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+    myConstraints.push_back(aRigidStart);
+    myConstraintMap[theConstraint].push_back(aRigidStart.h);
+    Slvs_Constraint aRigidEnd = Slvs_MakeConstraint(
+        ++myConstrMaxID, myID, SLVS_C_WHERE_DRAGGED, myWorkplane.h, 0,
+        myEntities[aMirrorLinePos].point[1], SLVS_E_UNKNOWN, SLVS_E_UNKNOWN, SLVS_E_UNKNOWN);
+    myConstraints.push_back(aRigidEnd);
+    myConstraintMap[theConstraint].push_back(aRigidEnd.h);
+  }
+  return true;
+}
+
 // ============================================================================
 //  Function: changeEntity
 //  Class:    SketchSolver_ConstraintGroup
index 36583e3381362b75fa054cc3983a0e39c33d3678..5816eee75f4b93dfea4abc9ce43dacc0647b178c 100644 (file)
@@ -67,6 +67,11 @@ class SketchSolver_ConstraintGroup
    *  \return \c true if the constraint added or updated successfully
    */
   bool changeRigidConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
+  /** \brief Adds or updates a mirror constraint in the group
+   *  \param[in] theConstraint constraint to be changed
+   *  \return \c true if the constraint added or updated successfully
+   */
+  bool changeMirrorConstraint(std::shared_ptr<SketchPlugin_Constraint> theConstraint);
 
   /** \brief Verifies the feature attributes are used in this group
    *  \param[in] theFeature constraint or any other object for verification of interaction
index d41d5dc1b3923cb528d91692324549114a8880b7..88dcd35c3fd45b27b56196ccb1e4f7ad9daef8a6 100644 (file)
@@ -78,14 +78,20 @@ void SketcherPrs_Tangent::drawLines(const Handle(Prs3d_Presentation)& thePrs, Qu
 
   std::shared_ptr<GeomAPI_Curve> aCurve1 = std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShape1));
   std::shared_ptr<GeomAPI_Curve> aCurve2 = std::shared_ptr<GeomAPI_Curve>(new GeomAPI_Curve(aShape2));
-  if (aCurve1->isLine()) {
+  if (aCurve1->isCircle() && aCurve2->isLine()) {
+    addLine(aGroup, SketchPlugin_Constraint::ENTITY_B());
+    GeomAdaptor_Curve aAdaptor(aCurve1->impl<Handle(Geom_Curve)>(), aCurve1->startParam(), aCurve1->endParam());
+    StdPrs_DeflectionCurve::Add(thePrs,aAdaptor,myDrawer);
+  } else if (aCurve1->isLine() && aCurve2->isCircle()) {
     addLine(aGroup, SketchPlugin_Constraint::ENTITY_A());
     GeomAdaptor_Curve aAdaptor(aCurve2->impl<Handle(Geom_Curve)>(), aCurve2->startParam(), aCurve2->endParam());
     StdPrs_DeflectionCurve::Add(thePrs,aAdaptor,myDrawer);
   } else {
-    addLine(aGroup, SketchPlugin_Constraint::ENTITY_B());
-    GeomAdaptor_Curve aAdaptor(aCurve1->impl<Handle(Geom_Curve)>(), aCurve1->startParam(), aCurve1->endParam());
-    StdPrs_DeflectionCurve::Add(thePrs,aAdaptor,myDrawer);
+    // Both curves are arcs
+    GeomAdaptor_Curve aAdaptor1(aCurve1->impl<Handle(Geom_Curve)>(), aCurve1->startParam(), aCurve1->endParam());
+    StdPrs_DeflectionCurve::Add(thePrs, aAdaptor1, myDrawer);
+    GeomAdaptor_Curve aAdaptor2(aCurve2->impl<Handle(Geom_Curve)>(), aCurve2->startParam(), aCurve2->endParam());
+    StdPrs_DeflectionCurve::Add(thePrs, aAdaptor2, myDrawer);
   }
 }