]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge branch 'master' into occ/bsplines
authorazv <azv@opencascade.com>
Wed, 29 Jan 2020 10:43:15 +0000 (13:43 +0300)
committerazv <azv@opencascade.com>
Wed, 29 Jan 2020 10:43:15 +0000 (13:43 +0300)
1  2 
src/ConstructionPlugin/ConstructionPlugin_Plugin.cpp
src/ModuleBase/ModuleBase_ModelWidget.h
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_SketcherMgr.cpp
src/PartSet/PartSet_SketcherMgr.h
src/PartSet/PartSet_Tools.cpp
src/PartSet/PartSet_Tools.h
src/SketchPlugin/SketchPlugin_msg_fr.ts
src/SketchPlugin/plugin-Sketch.xml

index e4f47673e86a92aa62e55f268e79979a090e03cd,855ce055a46a7eab21f9288174b5cabc3fc68bde..7e8ff1db5d49ba611905bf13954ccf76479a6507
@@@ -60,10 -60,10 +60,12 @@@ ConstructionPlugin_Plugin::Construction
      Config_Prop::IntSpin, SKETCH_WIDTH);
    Config_PropManager::registerProp(SKETCH_TAB_NAME, "angular_tolerance", "Angular tolerance",
      Config_Prop::DblSpin, "0.04");
 +  Config_PropManager::registerProp(SKETCH_TAB_NAME, "spline_weight", "Default spline weight",
 +    Config_Prop::DblSpin, "1.0");
    Config_PropManager::registerProp(SKETCH_TAB_NAME, "rotate_to_plane",
      "Rotate to plane when selected", Config_Prop::Boolean, "false");
+   Config_PropManager::registerProp(SKETCH_TAB_NAME, "operation_cursor",
+     "Cursor for Sketch operation", Config_Prop::Cursor, "0");
  
    // register this plugin
    ModelAPI_Session::get()->registerPlugin(this);
index f2187ee771d36e8815cd013247b3f9c90d067794,6e1122da17a902afd85c27fd2d8c5aff83f2877e..f4d864d51192a7940bc344a825d361473fa562a1
@@@ -255,8 -255,8 +255,8 @@@ Q_OBJEC
    /// \param theFeature a feature object
    /// \param theToStoreValue a value about necessity to store the widget value to the feature
    /// \param isUpdateFlushed a flag if update should be flushed on store value
 -  void setFeature(const FeaturePtr& theFeature, const bool theToStoreValue = false,
 -                  const bool isUpdateFlushed = true);
 +  virtual void setFeature(const FeaturePtr& theFeature, const bool theToStoreValue = false,
 +                          const bool isUpdateFlushed = true);
  
    /// Editing mode depends on mode of current operation. This value is defined by it.
    virtual void setEditingMode(bool isEditing) { myIsEditing = isEditing; }
  
    virtual bool isReadOnly() const { return !isEnabled(); }
  
+   /// Returns true if the widget should have access to external parts
+   bool canUseExternalParts() const { return myUseExternalParts; }
  signals:
    /// The signal about widget values are to be changed
    void beforeValuesChanged();
@@@ -461,6 -464,9 +464,9 @@@ private
    bool myFlushUpdateBlocked;
  
    bool myUpdateVisualAttributes;
+   /// A flag which indicates that current widget should have access to external parts
+   bool myUseExternalParts;
  };
  
  #endif
index 24070e7a7e180221c133e238fcfe7e16b1ce0e2f,feeda8b7185350a10e14402a6d8e818779ea7187..75fa7c49c2a7f1900c932942fa1505bb8566ef49
@@@ -22,7 -22,6 +22,7 @@@
  #include "PartSet_Validators.h"
  #include "PartSet_Tools.h"
  #include "PartSet_PreviewPlanes.h"
 +#include "PartSet_WidgetBSplinePoints.h"
  #include "PartSet_WidgetPoint2d.h"
  #include "PartSet_WidgetPoint2DFlyout.h"
  #include "PartSet_WidgetShapeSelector.h"
@@@ -40,7 -39,6 +40,7 @@@
  #include "PartSet_OverconstraintListener.h"
  #include "PartSet_TreeNodes.h"
  #include "PartSet_FieldStepPrs.h"
 +#include "PartSet_BSplineWidget.h"
  
  #include "PartSet_Filters.h"
  #include "PartSet_FilterInfinite.h"
@@@ -461,9 -459,9 +461,9 @@@ void PartSet_Module::updateSketcherOnSt
    }
    // It is switched off because of
    // Task #3067: 5.2.2 Drawing in the sketcher: change the mouse cursor arrow
-   //else if (sketchMgr()->isNestedSketchOperation(theOperation)) {
-   //  mySketchMgr->startNestedSketch(theOperation);
-   //}
+   else if (sketchMgr()->isNestedSketchOperation(theOperation)) {
+     mySketchMgr->startNestedSketch(theOperation);
+   }
  }
  
  //******************************************************
@@@ -806,12 -804,12 +806,12 @@@ bool PartSet_Module::createWidgets(cons
              return aProcessed;
          }
          const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
 -        AttributePtr anAttribute = PartSet_Tools::findAttributeBy2dPoint(anObject, aTDShape,
 -                                                               mySketchMgr->activeSketch());
 -        if (anAttribute.get()) {
 +        std::pair<AttributePtr, int> anAttribute =
 +            PartSet_Tools::findAttributeBy2dPoint(anObject, aTDShape, mySketchMgr->activeSketch());
 +        if (anAttribute.first.get()) {
            ModuleBase_WidgetFactory aFactory(theXmlRepr.toStdString(), workshop());
  
 -          const std::string anAttributeId = anAttribute->id();
 +          const std::string anAttributeId = anAttribute.first->id();
            aFactory.createWidget(aPropertyPanel->contentWidget(), anAttributeId);
  
            theWidgets = aFactory.getModelWidgets();
@@@ -917,27 -915,16 +917,27 @@@ ModuleBase_ModelWidget* PartSet_Module:
      aPointSelectorWgt->setSketcher(mySketchMgr->activeSketch());
      aWgt = aPointSelectorWgt;
    }
 +  else if (theType == "sketch-bspline_selector") {
 +    PartSet_WidgetBSplinePoints* aBSplineWgt =
 +        new PartSet_WidgetBSplinePoints(theParent, aWorkshop, theWidgetApi);
 +    aBSplineWgt->setSketch(mySketchMgr->activeSketch());
 +    aWgt = aBSplineWgt;
 +  }
    else if (theType == WDG_DOUBLEVALUE_EDITOR) {
      aWgt = new PartSet_WidgetEditor(theParent, aWorkshop, theWidgetApi);
    } else if (theType == "export_file_selector") {
      aWgt = new PartSet_WidgetFileSelector(theParent, aWorkshop, theWidgetApi);
    } else if (theType == "sketch_launcher") {
      aWgt = new PartSet_WidgetSketchCreator(theParent, this, theWidgetApi);
 -  } else if (theType == "module_choice") {
 +  }
 +  else if (theType == "module_choice") {
      aWgt = new ModuleBase_WidgetChoice(theParent, theWidgetApi);
      connect(aWgt, SIGNAL(itemSelected(ModuleBase_ModelWidget*, int)),
 -            this, SLOT(onChoiceChanged(ModuleBase_ModelWidget*, int)));
 +      this, SLOT(onChoiceChanged(ModuleBase_ModelWidget*, int)));
 +  } else if (theType == "bspline-panel") {
 +    PartSet_BSplineWidget* aPanel = new PartSet_BSplineWidget(theParent, theWidgetApi);
 +    //aPanel->setFeature(theFeature);
 +    aWgt = aPanel;
    }
    return aWgt;
  }
@@@ -1741,9 -1728,8 +1741,9 @@@ AttributePtr PartSet_Module::findAttrib
  
    if (aGeomShape.get()) {
      TopoDS_Shape aTDSShape = aGeomShape->impl<TopoDS_Shape>();
 -    return PartSet_Tools::findAttributeBy2dPoint(theObject, aTDSShape,
 -                                                 mySketchMgr->activeSketch());
 +    std::pair<AttributePtr, int> anAttrAndIndex =
 +        PartSet_Tools::findAttributeBy2dPoint(theObject, aTDSShape, mySketchMgr->activeSketch());
 +    return anAttrAndIndex.first;
    }
    return anAttribute;
  }
index 78237ef7f3bbc8e885da514f5ba9a9f9223e3ec8,27f9bf8d61a593223c16b7043cdb389ed5f3d59a..c57929240857943f38c965c34d622b7ffe75466f
@@@ -60,7 -60,6 +60,7 @@@
  #include <ModuleBase_ViewerFilters.h>
  
  #include <GeomDataAPI_Point2D.h>
 +#include <GeomDataAPI_Point2DArray.h>
  
  #include <GeomAPI_Shape.h>
  
  void getAttributesOrResults(const Handle(SelectMgr_EntityOwner)& theOwner,
                              const FeaturePtr& theFeature, const FeaturePtr& theSketch,
                              const ResultPtr& theResult,
 -                            std::set<AttributePtr>& theSelectedAttributes,
 +                            std::map<AttributePtr, int>& theSelectedAttributes,
                              std::set<ResultPtr>& theSelectedResults,
                              TopTools_MapOfShape& theShapes)
  {
      theShapes.Add(aShape);
      TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
      if (aShapeType == TopAbs_VERTEX) {
 -      AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(theFeature,
 -                                                                    aShape, theSketch);
 -      if (aPntAttr.get() != NULL)
 -        theSelectedAttributes.insert(aPntAttr);
 +      std::pair<AttributePtr, int> aPntAttrIndex =
 +          PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
 +      if (aPntAttrIndex.first.get() != NULL)
 +        theSelectedAttributes[aPntAttrIndex.first] = aPntAttrIndex.second;
      }
      else if (aShapeType == TopAbs_EDGE &&
               theSelectedResults.find(theResult) == theSelectedResults.end()) {
@@@ -227,15 -226,15 +227,15 @@@ void PartSet_SketcherMgr::onEnterViewPo
  
    // It is switched off because of
    // Task #3067: 5.2.2 Drawing in the sketcher: change the mouse cursor arrow
-   //  if (canChangeCursor(getCurrentOperation())) {
-   //    QCursor* aCurrentCursor = QApplication::overrideCursor();
-   //    if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
-   //      QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
+     if (canChangeCursor(getCurrentOperation())) {
+       QCursor* aCurrentCursor = QApplication::overrideCursor();
+       if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
+         QApplication::setOverrideCursor(PartSet_Tools::getOperationCursor());
    //#ifdef DEBUG_CURSOR
    //      qDebug("onEnterViewPort() : Qt::CrossCursor");
    //#endif
-   //    }
-   //  }
+       }
+     }
  
    if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
      return;
@@@ -267,12 -266,12 +267,12 @@@ void PartSet_SketcherMgr::onLeaveViewPo
    return;
    #endif
  
//  if (canChangeCursor(getCurrentOperation())) {
//    QApplication::restoreOverrideCursor();
+   if (canChangeCursor(getCurrentOperation())) {
+     QApplication::restoreOverrideCursor();
  //#ifdef DEBUG_CURSOR
  //    qDebug("onLeaveViewPort() : None");
  //#endif
//  }
+   }
  
    if (!isNestedCreateOperation(getCurrentOperation(), activeSketch()))
      return;
@@@ -457,9 -456,10 +457,10 @@@ void PartSet_SketcherMgr::onMousePresse
            }
          }
        }
-       else
-         isRelaunchEditing = !myCurrentSelection.contains(aSPFeature);
+       else {
+         if (myCurrentSelection.size() > 1)
+           isRelaunchEditing = !myCurrentSelection.contains(aSPFeature);
+       }
        if (isRelaunchEditing)
          aFOperation->commit();
  
@@@ -641,26 -641,26 +642,26 @@@ void PartSet_SketcherMgr::onMouseMoved(
      for (; anIt != aLast; anIt++) {
        FeaturePtr aFeature = anIt.key();
  
 -      std::set<AttributePtr> anAttributes = anIt.value().myAttributes;
 +      std::map<AttributePtr, int> anAttributes = anIt.value().myAttributes;
        // Process selection by attribute: the priority to the attribute
        if (!anAttributes.empty()) {
 -        std::set<AttributePtr>::const_iterator anAttIt = anAttributes.begin(),
 +        std::map<AttributePtr, int>::const_iterator anAttIt = anAttributes.begin(),
            anAttLast = anAttributes.end();
          for (; anAttIt != anAttLast; anAttIt++) {
 -          AttributePtr anAttr = *anAttIt;
 +          AttributePtr anAttr = anAttIt->first;
            if (anAttr.get() == NULL)
              continue;
            std::string aAttrId = anAttr->id();
            DataPtr aData = aFeature->data();
            if (aData->isValid()) {
 -            std::shared_ptr<GeomDataAPI_Point2D> aPoint =
 -              std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aData->attribute(aAttrId));
 -            if (aPoint.get() != NULL) {
 +            AttributePtr aPoint = aData->attribute(aAttrId);
 +            if (aPoint->attributeType() == GeomDataAPI_Point2D::typeId() ||
 +                aPoint->attributeType() == GeomDataAPI_Point2DArray::typeId()) {
                bool isImmutable = aPoint->setImmutable(true);
  
                std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage = std::shared_ptr
                  <ModelAPI_ObjectMovedMessage>(new ModelAPI_ObjectMovedMessage(this));
 -              aMessage->setMovedAttribute(aPoint);
 +              aMessage->setMovedAttribute(aPoint, anAttIt->second);
                aMessage->setOriginalPosition(anOriginalPosition);
                aMessage->setCurrentPosition(aCurrentPosition);
                Events_Loop::loop()->send(aMessage);
@@@ -1217,30 -1217,30 +1218,30 @@@ void PartSet_SketcherMgr::stopSketch(Mo
    workshop()->viewer()->set2dMode(false);
  }
  
//void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
//{
//  if (canChangeCursor(theOperation) && myIsMouseOverWindow) {
//    QCursor* aCurrentCursor = QApplication::overrideCursor();
//    if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
//      QApplication::setOverrideCursor(QCursor(Qt::CrossCursor));
+ void PartSet_SketcherMgr::startNestedSketch(ModuleBase_Operation* theOperation)
+ {
+   if (canChangeCursor(theOperation) && myIsMouseOverWindow) {
+     QCursor* aCurrentCursor = QApplication::overrideCursor();
+     if (!aCurrentCursor || aCurrentCursor->shape() != Qt::CrossCursor) {
      QApplication::setOverrideCursor(PartSet_Tools::getOperationCursor());
  //#ifdef DEBUG_CURSOR
  //      qDebug("startNestedSketch() : Qt::CrossCursor");
  //#endif
//    }
//  }
//}
+     }
+   }
+ }
  
  void PartSet_SketcherMgr::stopNestedSketch(ModuleBase_Operation* theOperation)
  {
    myIsMouseOverViewProcessed = true;
    operationMgr()->onValidateOperation();
    // when sketch nested operation is stopped the cursor should be restored unconditionally
-   //if (canChangeCursor(theOperation)) {
-     //QApplication::restoreOverrideCursor();
+   if (canChangeCursor(theOperation)) {
+     QApplication::restoreOverrideCursor();
  #ifdef DEBUG_CURSOR
      qDebug("stopNestedSketch() : None");
  #endif
-   //}
+   }
    /// improvement to deselect automatically all eventual selected objects, when
    // returning to the neutral point of the Sketcher
    bool isClearSelectionPossible = true;
@@@ -1686,7 -1686,7 +1687,7 @@@ void PartSet_SketcherMgr::getSelectionO
  
    FeatureToSelectionMap::const_iterator anIt = theSelection.find(theFeature);
    SelectionInfo anInfo = anIt.value();
 -  std::set<AttributePtr> aSelectedAttributes = anInfo.myAttributes;
 +  std::map<AttributePtr, int> aSelectedAttributes = anInfo.myAttributes;
    std::set<ResultPtr> aSelectedResults = anInfo.myResults;
  
    ModuleBase_IViewer* aViewer = theWorkshop->viewer();
        const TopoDS_Shape& aShape = anOwner->Shape();
        TopAbs_ShapeEnum aShapeType = aShape.ShapeType();
        if (aShapeType == TopAbs_VERTEX) {
 -        AttributePtr aPntAttr =
 +        std::pair<AttributePtr, int> aPntAttrIndex =
            PartSet_Tools::findAttributeBy2dPoint(theFeature, aShape, theSketch);
 -        if (aPntAttr.get() != NULL &&
 -            aSelectedAttributes.find(aPntAttr) != aSelectedAttributes.end())
 +        if (aPntAttrIndex.first.get() != NULL &&
 +            aSelectedAttributes.find(aPntAttrIndex.first) != aSelectedAttributes.end())
            theOwnersToSelect.Add(anOwner);
          else if (isSameShape && anInfo.myLocalSelectedShapes.Contains(aShape)) {
            theOwnersToSelect.Add(anOwner);
@@@ -2271,8 -2271,9 +2272,9 @@@ void PartSet_SketcherMgr::customizeSket
    if (aShapeType != 6/*an edge*/ && aShapeType != 7/*a vertex*/ && aShapeType != 0/*compound*/)
      return;
  
+   int aWidth = Config_PropManager::integer("Visualization", "sketch_line_width");
    if (isExternal(aFeature)) {
-     thePrs->setWidth(1);
+     thePrs->setWidth(isIncludeToResult(aFeature)? aWidth : 1);
      return;
    }
    std::string aKind = aFeature->getKind();
        thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE_AUXILIARY());
      }
      else {
-       int aWidth = Config_PropManager::integer("Visualization", "sketch_line_width");
        thePrs->setWidth(aWidth);
        thePrs->setLineStyle(SketchPlugin_SketchEntity::SKETCH_LINE_STYLE());
      }
index defc3465b54fc4de24a16549679d8635f7d88b42,67640b0184c9fa779fa1103ac6f72c1228e7ddf8..97fb2c720cf77533f3e58e33f6975d1e4f957e38
@@@ -137,8 -137,7 +137,8 @@@ public
    /// Struct to define selection model information to store/restore selection
    struct SelectionInfo
    {
 -    std::set<AttributePtr> myAttributes; /// the selected attributes
 +    /// the selected attributes and indices of points if array
 +    std::map<AttributePtr, int> myAttributes;
      std::set<ResultPtr> myResults; /// the selected results
      TopoDS_Shape myFirstResultShape; /// the first shape of feature result
      TopTools_MapOfShape myLocalSelectedShapes; /// shapes of local selection
@@@ -220,7 -219,7 +220,7 @@@ public
  
    /// Starts sketch operation, connects to the opeation property panel
    /// \param theOperation a committed operation
-   //void startNestedSketch(ModuleBase_Operation* theOperation);
+   void startNestedSketch(ModuleBase_Operation* theOperation);
  
    /// Stop sketch operation, disconnects from the opeation property panel
    /// \param theOperation a stopped operation
index 50f9efa2ed9c28950849098bb5d1127e0e585085,83476b096d03d4bd9c0f64e99b4b8c6e00367bd8..09f2e143726776d661a379a62fd906eacffb590c
@@@ -49,7 -49,6 +49,7 @@@
  #include <GeomDataAPI_Point.h>
  #include <GeomDataAPI_Dir.h>
  #include <GeomDataAPI_Point2D.h>
 +#include <GeomDataAPI_Point2DArray.h>
  #include <GeomAPI_Pln.h>
  #include <GeomAPI_Pnt2d.h>
  #include <GeomAPI_Pnt.h>
@@@ -444,9 -443,9 +444,9 @@@ GeomShapePtr PartSet_Tools::findShapeBy
                // attribute, returns the shape
                PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(theWorkshop->module());
                PartSet_SketcherMgr* aSketchMgr = aModule->sketchMgr();
 -              AttributePtr aPntAttr = PartSet_Tools::findAttributeBy2dPoint(anAttributeFeature,
 -                                                        aBRepShape, aSketchMgr->activeSketch());
 -              if (aPntAttr.get() != NULL && aPntAttr == theAttribute) {
 +              std::pair<AttributePtr, int> aPntAttrIndex = PartSet_Tools::findAttributeBy2dPoint(
 +                  anAttributeFeature, aBRepShape, aSketchMgr->activeSketch());
 +              if (aPntAttrIndex.first.get() != NULL && aPntAttrIndex.first == theAttribute) {
                  aShape = std::shared_ptr<GeomAPI_Shape>(new GeomAPI_Shape);
                  aShape->setImpl(new TopoDS_Shape(aBRepShape));
                  break;
@@@ -484,24 -483,6 +484,24 @@@ std::shared_ptr<GeomAPI_Pnt2d> PartSet_
    return std::shared_ptr<GeomAPI_Pnt2d>(new GeomAPI_Pnt2d(aX, anY));
  }
  
 +std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPnt2d(const Handle(V3d_View)& theView,
 +                                                       const TopoDS_Shape& theShape,
 +                                                       const FeaturePtr& theSketch)
 +{
 +  GeomPnt2dPtr aPoint2D;
 +  if (!theShape.IsNull() && theShape.ShapeType() == TopAbs_VERTEX) {
 +    const TopoDS_Vertex& aVertex = TopoDS::Vertex(theShape);
 +    if (!aVertex.IsNull()) {
 +      // the case when the point is taken from the existing vertex
 +      gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
 +      double aX, aY;
 +      PartSet_Tools::convertTo2D(aPoint, theSketch, theView, aX, aY);
 +      aPoint2D.reset(new GeomAPI_Pnt2d(aX, aY));
 +    }
 +  }
 +  return aPoint2D;
 +}
 +
  FeaturePtr findFirstCoincidenceByData(const DataPtr& theData,
                                        std::shared_ptr<GeomAPI_Pnt2d> thePoint)
  {
@@@ -649,44 -630,12 +649,44 @@@ std::shared_ptr<GeomAPI_Pnt2d> PartSet_
    return aPnt;
  }
  
 -AttributePtr PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
 -                                                   const TopoDS_Shape theShape,
 -                                                   FeaturePtr theSketch)
 +class PointWrapper
 +{
 +public:
 +  PointWrapper(AttributePtr theAttribute)
 +    : myPoint(std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute)),
 +      myArray(std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute))
 +  {}
 +
 +  int size() const { return myPoint.get() ? 1 : (myArray.get() ? myArray->size() : 0); }
 +
 +  GeomPointPtr point(int theIndex, FeaturePtr theSketch)
 +  {
 +    GeomPnt2dPtr aP2d;
 +    if (myPoint.get())
 +      aP2d = myPoint->pnt();
 +    else if (myArray.get())
 +      aP2d = myArray->pnt(theIndex);
 +
 +    GeomPointPtr aP3d;
 +    if (aP2d.get())
 +      aP3d = PartSet_Tools::convertTo3D(aP2d->x(), aP2d->y(), theSketch);
 +    return aP3d;
 +  }
 +
 +  bool isArray() const { return myArray.get(); }
 +
 +private:
 +  AttributePoint2DPtr myPoint;
 +  AttributePoint2DArrayPtr myArray;
 +};
 +
 +std::pair<AttributePtr, int> PartSet_Tools::findAttributeBy2dPoint(ObjectPtr theObj,
 +                                                                   const TopoDS_Shape theShape,
 +                                                                   FeaturePtr theSketch)
  {
  
    AttributePtr anAttribute;
 +  int aPointIndex = -1;
    FeaturePtr aFeature = ModelAPI_Feature::feature(theObj);
    if (aFeature) {
      if (theShape.ShapeType() == TopAbs_VERTEX) {
          // find the given point in the feature attributes
          std::list<AttributePtr> anAttiributes =
            aFeature->data()->attributes(GeomDataAPI_Point2D::typeId());
 +        std::list<AttributePtr> anArrays =
 +          aFeature->data()->attributes(GeomDataAPI_Point2DArray::typeId());
 +        anAttiributes.insert(anAttiributes.end(), anArrays.begin(), anArrays.end());
 +
          std::list<AttributePtr>::const_iterator anIt = anAttiributes.begin(),
                                                  aLast = anAttiributes.end();
          double aMinDistance = 1.e-6; // searching for point with minimal distance and < 1.e-6
          for (; anIt != aLast && !anAttribute; anIt++) {
 -          std::shared_ptr<GeomDataAPI_Point2D> aCurPoint =
 -            std::dynamic_pointer_cast<GeomDataAPI_Point2D>(*anIt);
 -          if (!aCurPoint->isInitialized())
 -            continue;
 -
 -          std::shared_ptr<GeomAPI_Pnt> aPnt =
 -            convertTo3D(aCurPoint->x(), aCurPoint->y(), theSketch);
 -          if (aPnt) {
 -            double aDistance = aPnt->distance(aValue);
 -            if (aDistance < aMinDistance) {
 -              anAttribute = aCurPoint;
 -              aMinDistance = aPnt->distance(aValue);
 +          PointWrapper aWrapper(*anIt);
 +          for (int anIndex = 0, aSize = aWrapper.size(); anIndex < aSize; ++anIndex) {
 +            std::shared_ptr<GeomAPI_Pnt> aPnt = aWrapper.point(anIndex, theSketch);
 +            if (aPnt) {
 +              double aDistance = aPnt->distance(aValue);
 +              if (aDistance < aMinDistance) {
 +                anAttribute = *anIt;
 +                if (aWrapper.isArray())
 +                  aPointIndex = anIndex;
 +                aMinDistance = aPnt->distance(aValue);
 +              }
              }
            }
          }
        }
      }
    }
 -  return anAttribute;
 +  return std::pair<AttributePtr, int>(anAttribute, aPointIndex);
  }
  
  void PartSet_Tools::sendSubFeaturesEvent(const CompositeFeaturePtr& theComposite,
@@@ -905,3 -851,17 +905,17 @@@ double PartSet_Tools::getDefaultTranspa
  {
    return Config_PropManager::integer("Visualization", "shaper_default_transparency") / 100.;
  }
+ QCursor PartSet_Tools::getOperationCursor()
+ {
+   int aId = Config_PropManager::integer(SKETCH_TAB_NAME, "operation_cursor");
+   switch (aId) {
+   case 0:
+     return QCursor(Qt::ArrowCursor);
+   case 1:
+     return QCursor(Qt::CrossCursor);
+   case 2:
+     return QCursor(Qt::PointingHandCursor);
+   }
+   return QCursor();
+ }
index 4e82cb45182a29a30bf370ffabda33d684047c9c,250e82a19119653cb83bf5b71f2b0768026f4f68..574ecc5b4221c00a379af6b1f7e5f9b3961cf04d
@@@ -26,6 -26,7 +26,7 @@@
  
  #include <QPoint>
  #include <QList>
+ #include <QCursor>
  
  #include <ModelAPI_CompositeFeature.h>
  #include <ModelAPI_Object.h>
@@@ -192,11 -193,9 +193,11 @@@ public
    * \param theObj - an object
    * \param theShape - a Shape
    * \param theSketch - a Sketch to get a plane of converting to 2d
 +  * \return Found attribute and index of point if the attribute is an array
    */
 -  static AttributePtr findAttributeBy2dPoint(ObjectPtr theObj, const TopoDS_Shape theShape,
 -                                             FeaturePtr theSketch);
 +  static std::pair<AttributePtr, int> findAttributeBy2dPoint(ObjectPtr theObj,
 +                                                             const TopoDS_Shape theShape,
 +                                                             FeaturePtr theSketch);
  
    /**
    * Finds an attribute value in attribute reference attribute value
  
    /**
    * Convertes parameters into a geom point
 -  * \theEvent a Qt event to find mouse position
 +  * \param theEvent a Qt event to find mouse position
    * \param theWindow view window to define eye of view
    * \param theSketch to convert 3D point coordinates into coorditates of the sketch plane
    */
                                                   ModuleBase_IViewWindow* theWindow,
                                                   const FeaturePtr& theSketch);
  
 +  /** Returns point 2d from selected shape
 +   *  \param theView a view window
 +   *  \param theShape a vertex shape
 +   *  \param theX an output value of X coordinate
 +   *  \param theY an output value of Y coordinate
 +   */
 +  static std::shared_ptr<GeomAPI_Pnt2d> getPnt2d(const Handle(V3d_View)& theView,
 +                                                 const TopoDS_Shape& theShape,
 +                                                 const FeaturePtr& theSketch);
 +
    /**
    * Gets all references to the feature, take coincidence constraint features, get point 2d attributes
    * and compare the point value to be equal with the given. Returns the first feature, which has
    * Returns default transparency value
    */
    static double getDefaultTransparency();
+   /**
+   * Returns cursor according to (SKETCH_TAB_NAME, "operation_cursor") property value
+   */
+   static QCursor getOperationCursor();
  };
  
  #endif
index c54a4092c4332fb368cf731ba1e9aa0b5b7dcd73,5e21e2514e278de653799b4c23be93a89287767d..2c6c284e770bc86fb34bbe7ac68c5906aa30dc6b
        <translation>Type d&apos;angle</translation>
      </message>
      <message>
-       <source>Complementary</source>
-       <translation>Complémentaire</translation>
+       <source>Supplementary</source>
+       <translation>Supplémentaire</translation>
      </message>
      <message>
        <source>Direct</source>
      </message>
    </context>
  
 +  <context>
 +    <name>SketchBSpline</name>
 +    <message>
 +        <source>Number of B-spline poles should be 2 or more</source>
 +        <translation>Le nombre de pôles B-spline doit être de 2 ou plus</translation>
 +    </message>
 +  </context>
 +
  </TS>
index 0acbf60d136742ede354b17bd4212e0b26e0bf1c,61c0319a701558e3ec315ce042b906c2c1c25422..d12e746ea1616956c50296e468de8480baaec6c0
@@@ -6,7 -6,6 +6,7 @@@
          nested="SketchPoint SketchIntersectionPoint SketchLine
                  SketchCircle SketchMacroCircle SketchArc SketchMacroArc
                  SketchEllipse SketchMacroEllipse SketchEllipticArc SketchMacroEllipticArc
 +                SketchBSpline SketchMacroBSpline SketchMacroBSplinePeriodic SketchBSplinePeriodic
                  SketchRectangle
                  SketchProjection
                  SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintDistanceHorizontal SketchConstraintDistanceVertical
        </feature>
      </group>
  
 +    <group id="Parametric curves">
 +      <!-- SketchBSpline is a hidden feature. It is created inside SketchMacroBSpline. -->
 +      <feature id="SketchBSpline"
 +               title="B-spline"
 +               tooltip="Create B-spline curve"
 +               icon="icons/Sketch/bspline.png"
 +               helpfile="bsplineFeature.html"
 +               internal="1">
 +        <bspline-panel id="poles"
 +                       weights="weights"
 +                       title="Poles and weights"
 +                       tooltip="B-spline poles and weights"
 +                       enable_value="enable_by_preferences">
 +          <validator id="SketchPlugin_BSplineValidator"/>
 +        </bspline-panel>
 +        <boolvalue id="Auxiliary"
 +                   label="Auxiliary"
 +                   default="false"
 +                   tooltip="Construction element"
 +                   obligatory="0"
 +                   change_visual_attributes="true"/>
 +      </feature>
 +
 +      <!-- SketchBSplinePeriodic is a hidden feature. It is created inside SketchMacroBSplinePeriodic. -->
 +      <feature id="SketchBSplinePeriodic"
 +               title="Periodic B-spline"
 +               tooltip="Create periodic B-spline curve"
 +               icon="icons/Sketch/bspline_p.png"
 +               helpfile="bsplineFeature.html"
 +               internal="1">
 +        <bspline-panel id="poles"
 +                       weights="weights"
 +                       title="Poles and weights"
 +                       tooltip="B-spline poles and weights"
 +                       enable_value="enable_by_preferences">
 +          <validator id="SketchPlugin_BSplineValidator"/>
 +        </bspline-panel>
 +        <boolvalue id="Auxiliary"
 +                   label="Auxiliary"
 +                   default="false"
 +                   tooltip="Construction element"
 +                   obligatory="0"
 +                   change_visual_attributes="true"/>
 +      </feature>
 +
 +      <!-- SketchMacroBSpline -->
 +      <feature id="SketchMacroBSpline"
 +               title="B-spline"
 +               tooltip="Create B-spline curve"
 +               icon="icons/Sketch/bspline.png"
 +               helpfile="bsplineFeature.html">
 +        <sketch-bspline_selector id="poles"
 +                                 weights="weights"
 +                                 reference_attribute="poles_ref"
 +                                 title="Poles and weights"
 +                                 tooltip="B-spline poles and weights"
 +                                 enable_value="enable_by_preferences">
 +          <validator id="SketchPlugin_BSplineValidator"/>
 +        </sketch-bspline_selector>
 +        <boolvalue id="need_control_poly"
 +                   label="Create control polygon"
 +                   default="true"
 +                   tooltip="Specify if the control polygon should be created"/>
 +        <boolvalue id="Auxiliary"
 +                   label="Auxiliary"
 +                   default="false"
 +                   tooltip="Construction element"
 +                   obligatory="0"
 +                   change_visual_attributes="true"/>
 +      </feature>
 +
 +      <!-- SketchMacroBSplinePeriodic -->
 +      <feature id="SketchMacroBSplinePeriodic"
 +               title="Periodic B-spline"
 +               tooltip="Create periodic B-spline curve"
 +               icon="icons/Sketch/bspline_p.png"
 +               helpfile="bsplineFeature.html">
 +        <sketch-bspline_selector id="poles"
 +                                 weights="weights"
 +                                 reference_attribute="poles_ref"
 +                                 title="Poles and weights"
 +                                 tooltip="B-spline poles and weights"
 +                                 enable_value="enable_by_preferences">
 +          <validator id="SketchPlugin_BSplineValidator"/>
 +        </sketch-bspline_selector>
 +        <boolvalue id="need_control_poly"
 +                   label="Create control polygon"
 +                   default="true"
 +                   tooltip="Specify if the control polygon should be created"/>
 +        <boolvalue id="Auxiliary"
 +                   label="Auxiliary"
 +                   default="false"
 +                   tooltip="Construction element"
 +                   obligatory="0"
 +                   change_visual_attributes="true"/>
 +      </feature>
 +    </group>
 +
      <group id="Segmentation">
        <!--  SketchSplit  -->
        <feature id="SketchSplit" title="Split"
            buttons_dir="horizontal"
            label="Angle type"
            tooltip="Type of angle"
-           string_list="Direct Complementary Additional"
+           string_list="Direct Supplementary Additional"
            icons_list="icons/Sketch/angle_direct.png icons/Sketch/angle_complementary.png icons/Sketch/angle_backward.png"
            default="0"
            />