Salome HOME
Issue #17347: B-Splines in Sketcher
authorazv <azv@opencascade.com>
Sat, 28 Dec 2019 09:41:35 +0000 (12:41 +0300)
committerazv <azv@opencascade.com>
Sat, 28 Dec 2019 10:51:17 +0000 (13:51 +0300)
Initial implementation of non-periodic B-spline curves.

55 files changed:
lcov_reports.sh
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.cpp
src/GeomAlgoAPI/GeomAlgoAPI_EdgeBuilder.h
src/GeomData/CMakeLists.txt
src/GeomData/GeomData_Point2DArray.cpp [new file with mode: 0644]
src/GeomData/GeomData_Point2DArray.h [new file with mode: 0644]
src/GeomDataAPI/CMakeLists.txt
src/GeomDataAPI/GeomDataAPI_Point2DArray.cpp [new file with mode: 0644]
src/GeomDataAPI/GeomDataAPI_Point2DArray.h [new file with mode: 0644]
src/Model/Model_AttributeRefAttrList.cpp
src/Model/Model_Data.cpp
src/ModelAPI/ModelAPI_Events.cpp
src/ModelAPI/ModelAPI_Events.h
src/PartSet/CMakeLists.txt
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_Tools.cpp
src/PartSet/PartSet_Tools.h
src/PartSet/PartSet_WidgetBSplinePoints.cpp [new file with mode: 0644]
src/PartSet/PartSet_WidgetBSplinePoints.h [new file with mode: 0644]
src/PartSet/PartSet_WidgetPoint2d.cpp
src/PartSet/PartSet_WidgetPoint2d.h
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_BSpline.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_BSpline.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_ConstraintCoincidenceInternal.cpp
src/SketchPlugin/SketchPlugin_ConstraintCoincidenceInternal.h
src/SketchPlugin/SketchPlugin_MacroBSpline.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_MacroBSpline.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/SketchPlugin_Validators.cpp
src/SketchPlugin/SketchPlugin_Validators.h
src/SketchPlugin/icons/bspline.png [new file with mode: 0644]
src/SketchPlugin/icons/bspline_p.png [new file with mode: 0644]
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/PlaneGCSSolver/CMakeLists.txt
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Defs.h
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_EdgeWrapper.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointArrayWrapper.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointArrayWrapper.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarArrayWrapper.cpp [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarArrayWrapper.h [new file with mode: 0644]
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarWrapper.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.h
src/SketchSolver/SketchSolver_Constraint.cpp
src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp
src/SketchSolver/SketchSolver_ConstraintMovement.cpp
src/SketchSolver/SketchSolver_ConstraintMovement.h
src/SketchSolver/SketchSolver_Group.cpp
src/SketchSolver/SketchSolver_Group.h
src/SketchSolver/SketchSolver_Manager.cpp
src/SketchSolver/SketchSolver_Manager.h

index cd094cf1528fb31670e24af8f0b45dfd6e2d4ce3..e2b48e3cade1f7c88ffacb85eeb6b63239075f04 100755 (executable)
@@ -9,8 +9,7 @@ lcov --capture --directory ${BUILD_DIR} --no-external --base-directory ${SOURCES
 # make a working copy of report
 cp -f coverage.info.noext covfile
 # remove all reports of GUI and external parts (for all the next kinds of reports)
-# RefAttrList is unused type of attribute for now
-for MASK in '*wrap*' 'moc_*' 'XAO_*' 'SketcherPrs_*' 'GeomAlgoImpl_*' 'ModuleBase_*' '*Widget*' '*Splitter*' '*RefAttrList*'; do
+for MASK in '*wrap*' 'moc_*' 'XAO_*' 'SketcherPrs_*' 'GeomAlgoImpl_*' 'ModuleBase_*' '*Widget*' '*Splitter*'; do
 lcov -r covfile ${MASK} --output-file covfile_res -q
 mv -f covfile_res covfile
 done
index 9bfc1a50a20364ac3d8c4af28ca2c23fb34d9bd8..4e42c0a92adbf69ce6f31aa3dcc4a9ac8941b748 100644 (file)
@@ -28,6 +28,7 @@
 #include <TopoDS_Face.hxx>
 #include <TopoDS.hxx>
 #include <BRep_Tool.hxx>
+#include <Geom_BSplineCurve.hxx>
 #include <Geom_Plane.hxx>
 #include <Geom_CylindricalSurface.hxx>
 #include <Geom_RectangularTrimmedSurface.hxx>
@@ -266,3 +267,52 @@ std::shared_ptr<GeomAPI_Edge> GeomAlgoAPI_EdgeBuilder::ellipticArc(
   aRes->setImpl(new TopoDS_Shape(anEdge));
   return aRes;
 }
+
+GeomEdgePtr GeomAlgoAPI_EdgeBuilder::bspline(const std::vector<GeomPointPtr>& thePoles,
+                                             const std::vector<double>& theWeights,
+                                             const bool thePeriodic)
+{
+  int aDegree = 3;
+  if ((int)thePoles.size() <= aDegree)
+    aDegree = (int)thePoles.size() - 1;
+  if (aDegree <= 0)
+    return GeomEdgePtr();
+
+  int aNbKnots = (int)thePoles.size() - aDegree + 1;
+
+  // collect arrays of poles, weights, knots and multiplicities
+  TColgp_Array1OfPnt aPoles(1, (int)thePoles.size());
+  TColStd_Array1OfReal aWeights(1, (int)theWeights.size());
+  TColStd_Array1OfReal aKnots(1, aNbKnots);
+  TColStd_Array1OfInteger aMults(1, aNbKnots);
+
+  int anIndex = 1;
+  for (std::vector<GeomPointPtr>::const_iterator aPIt = thePoles.begin();
+       aPIt != thePoles.end(); ++aPIt, ++anIndex)
+    aPoles.SetValue(anIndex, gp_Pnt((*aPIt)->x(), (*aPIt)->y(), (*aPIt)->z()));
+  anIndex = 1;
+  for (std::vector<double>::const_iterator aWIt = theWeights.begin();
+       aWIt != theWeights.end(); ++aWIt, ++anIndex)
+    aWeights.SetValue(anIndex, *aWIt);
+  anIndex = 1;
+  static const double aStartParam = 0.0;
+  static const double aEndParam = 1.0;
+  double aStep = aEndParam / (aNbKnots - 1);
+  for (double aKnot = aStartParam; anIndex < aNbKnots; ++anIndex, aKnot += aStep)
+    aKnots.SetValue(anIndex, aKnot);
+  aKnots.ChangeLast() = aEndParam;
+  anIndex = 1;
+  aMults.SetValue(anIndex, aDegree + 1);
+  for (++anIndex; anIndex < aNbKnots; ++anIndex)
+    aMults.SetValue(anIndex, 1);
+  aMults.SetValue(aNbKnots, aDegree + 1);
+
+  Handle(Geom_BSplineCurve) aCurve =
+      new Geom_BSplineCurve(aPoles, aWeights, aKnots, aMults, aDegree, thePeriodic);
+
+  BRepBuilderAPI_MakeEdge anEdgeBuilder(aCurve, aStartParam, aEndParam);
+  GeomEdgePtr aRes(new GeomAPI_Edge);
+  TopoDS_Edge anEdge = anEdgeBuilder.Edge();
+  aRes->setImpl(new TopoDS_Shape(anEdge));
+  return aRes;
+}
index 245e97f05888c0795f2d21e37dde3f242ae10e05..d6185f3f51511d26c108b6afee12f1b8039946e7 100644 (file)
@@ -27,6 +27,7 @@
 #include <GeomAPI_Lin.h>
 #include <GeomAPI_Circ.h>
 #include <memory>
+#include <vector>
 
 /**\class GeomAlgoAPI_EdgeBuilder
  * \ingroup DataAlgo
@@ -89,6 +90,11 @@ class GEOMALGOAPI_EXPORT GeomAlgoAPI_EdgeBuilder
       const double                        theMinorRadius,
       const std::shared_ptr<GeomAPI_Pnt>& theStart,
       const std::shared_ptr<GeomAPI_Pnt>& theEnd);
+
+  /// Creates B-spline edge
+  static GeomEdgePtr bspline(const std::vector<GeomPointPtr>& thePoles,
+                             const std::vector<double>& theWeights,
+                             const bool thePeriodic);
 };
 
 #endif
index d6ef692308a1190888a64974b3f053528bf820f4..2b281396cd48ffbf6574e0eb6d342f046839072a 100644 (file)
@@ -24,12 +24,14 @@ SET(PROJECT_HEADERS
     GeomData_Point.h
     GeomData_Dir.h
     GeomData_Point2D.h
+    GeomData_Point2DArray.h
 )
 
 SET(PROJECT_SOURCES
     GeomData_Point.cpp
     GeomData_Dir.cpp
     GeomData_Point2D.cpp
+    GeomData_Point2DArray.cpp
 )
 
 SET(PROJECT_LIBRARIES
diff --git a/src/GeomData/GeomData_Point2DArray.cpp b/src/GeomData/GeomData_Point2DArray.cpp
new file mode 100644 (file)
index 0000000..27376b9
--- /dev/null
@@ -0,0 +1,115 @@
+// Copyright (C) 2019-2020  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 "GeomData_Point2DArray.h"
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <ModelAPI_Data.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_Expression.h>
+#include <ModelAPI_Feature.h>
+
+#include <cassert>
+
+GeomData_Point2DArray::GeomData_Point2DArray(TDF_Label& theLabel)
+  : myLab(theLabel)
+{
+  reinit();
+}
+
+void GeomData_Point2DArray::reinit()
+{
+  // check the attribute could be already presented in this doc (after load document)
+  myIsInitialized = myLab.FindAttribute(TDataStd_RealArray::GetID(), myArray) == Standard_True;
+}
+
+bool GeomData_Point2DArray::assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther)
+{
+  std::shared_ptr<GeomData_Point2DArray> anOther =
+      std::dynamic_pointer_cast<GeomData_Point2DArray>(theOther);
+  if (!anOther)
+    return false;
+
+  setSize(anOther->size());
+  myArray->ChangeArray(anOther->myArray->Array(), false);
+}
+
+int GeomData_Point2DArray::size()
+{
+  if (myArray.IsNull() || !myArray->IsValid()) {
+    // this could be on undo and then redo creation of the attribute
+    // in result creation it may be uninitialized
+    myIsInitialized = myLab.FindAttribute(TDataStd_RealArray::GetID(), myArray) == Standard_True;
+  }
+  // checking the validity because attribute (as a field) may be presented,
+  // but without label: it is undoed
+  return (myArray.IsNull() || !myArray->IsValid()) ? 0 : myArray->Length() / 2;
+}
+
+void GeomData_Point2DArray::setSize(const int theSize)
+{
+  int aValuesSize = 2 * theSize;
+  if (myArray.IsNull() || !myArray->IsValid()) { // create array if it is not done yet
+    if (aValuesSize != 0) { // if size is zero, nothing to do (null array means there is no array)
+      myArray = TDataStd_RealArray::Set(myLab, 0, aValuesSize - 1);
+      owner()->data()->sendAttributeUpdated(this);
+    }
+  }
+  else { // reset the old array
+    if (aValuesSize) {
+      if (aValuesSize != myArray->Length()) { // old data is not keept, a new array is created
+        Handle(TColStd_HArray1OfReal) aNewArray = new TColStd_HArray1OfReal(0, aValuesSize - 1);
+        myArray->ChangeArray(aNewArray);
+        owner()->data()->sendAttributeUpdated(this);
+      }
+    }
+    else { // size is zero => array must be erased
+      if (!myArray.IsNull()) {
+        myArray.Nullify();
+        myLab.ForgetAttribute(TDataStd_RealArray::GetID());
+        owner()->data()->sendAttributeUpdated(this);
+      }
+    }
+  }
+}
+
+void GeomData_Point2DArray::setPnt(const int theIndex,
+                                   const double theX,
+                                   const double theY)
+{
+  if (myArray->Value(2 * theIndex) != theX || myArray->Value(2 * theIndex + 1) != theY) {
+    myArray->SetValue(2 * theIndex, theX);
+    myArray->SetValue(2 * theIndex + 1, theY);
+    owner()->data()->sendAttributeUpdated(this);
+  }
+}
+
+void GeomData_Point2DArray::setPnt(const int theIndex, const GeomPnt2dPtr& thePoint)
+{
+  setPnt(theIndex, thePoint->x(), thePoint->y());
+}
+
+GeomPnt2dPtr GeomData_Point2DArray::pnt(const int theIndex)
+{
+  GeomPnt2dPtr aPoint;
+  if (theIndex >= 0 && theIndex * 2 < myArray->Length())
+    aPoint.reset(new GeomAPI_Pnt2d(myArray->Value(2 * theIndex), myArray->Value(2 * theIndex + 1)));
+  return aPoint;
+}
diff --git a/src/GeomData/GeomData_Point2DArray.h b/src/GeomData/GeomData_Point2DArray.h
new file mode 100644 (file)
index 0000000..8f3f739
--- /dev/null
@@ -0,0 +1,70 @@
+// Copyright (C) 2019-2020  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 GeomData_Point2DArray_H_
+#define GeomData_Point2DArray_H_
+
+#include "GeomData.h"
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <TDataStd_RealArray.hxx>
+#include <TDF_Label.hxx>
+
+/** \class GeomData_Point2DArray
+ *  \ingroup DataModel
+ *  \brief Attribute that contains an array of 2D points.
+ */
+class GeomData_Point2DArray : public GeomDataAPI_Point2DArray
+{
+  TDF_Label myLab; ///< the main label of the attribute
+  Handle_TDataStd_RealArray myArray; ///< array that keeps all coordinates of the points
+
+public:
+  /// Copy values from another array
+  /// \return \c true if the copy was successful
+  GEOMDATA_EXPORT virtual bool assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther);
+
+  /// Returns the size of the array (zero means that it is empty)
+  GEOMDATA_EXPORT virtual int size();
+
+  /// Sets the new size of the array. The previous data is erased.
+  GEOMDATA_EXPORT virtual void setSize(const int theSize);
+
+  /// Defines the value of the array by index [0; size-1]
+  GEOMDATA_EXPORT virtual void setPnt(const int theIndex,
+                                      const double theX, const double theY);
+
+  /// Defines the value of the array by index [0; size-1]
+  GEOMDATA_EXPORT virtual void setPnt(const int theIndex,
+                                      const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
+
+  /// Returns the value by the index
+  GEOMDATA_EXPORT virtual std::shared_ptr<GeomAPI_Pnt2d> pnt(const int theIndex);
+
+protected:
+  /// Initializes attributes
+  GEOMDATA_EXPORT GeomData_Point2DArray(TDF_Label& theLabel);
+  /// Reinitializes the internal state of the attribute (may be needed on undo/redo, abort, etc)
+  virtual void reinit();
+
+  friend class Model_Data;
+};
+
+#endif
index ecc087c26d2dfbc9722f0fbc67ecb5d0e8fd2b28..fde2672d6975ce651a6c4ed51e2a6264f81e6289 100644 (file)
@@ -27,12 +27,14 @@ SET(PROJECT_HEADERS
     GeomDataAPI_Point.h
     GeomDataAPI_Dir.h
     GeomDataAPI_Point2D.h
+    GeomDataAPI_Point2DArray.h
 )
 
 SET(PROJECT_SOURCES
     GeomDataAPI_Point.cpp
     GeomDataAPI_Dir.cpp
     GeomDataAPI_Point2D.cpp
+    GeomDataAPI_Point2DArray.cpp
 )
 
 SET(PROJECT_LIBRARIES
diff --git a/src/GeomDataAPI/GeomDataAPI_Point2DArray.cpp b/src/GeomDataAPI/GeomDataAPI_Point2DArray.cpp
new file mode 100644 (file)
index 0000000..fcd9a8e
--- /dev/null
@@ -0,0 +1,33 @@
+// Copyright (C) 2019-2020  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 <GeomDataAPI_Point2DArray.h>
+
+std::string GeomDataAPI_Point2DArray::attributeType()
+{
+  return typeId();
+}
+
+GeomDataAPI_Point2DArray::GeomDataAPI_Point2DArray()
+{
+}
+
+GeomDataAPI_Point2DArray::~GeomDataAPI_Point2DArray()
+{
+}
diff --git a/src/GeomDataAPI/GeomDataAPI_Point2DArray.h b/src/GeomDataAPI/GeomDataAPI_Point2DArray.h
new file mode 100644 (file)
index 0000000..1976b16
--- /dev/null
@@ -0,0 +1,74 @@
+// Copyright (C) 2019-2020  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 GeomDataAPI_Point2DArray_H_
+#define GeomDataAPI_Point2DArray_H_
+
+#include <GeomDataAPI.h>
+#include <ModelAPI_Attribute.h>
+
+class GeomAPI_Pnt2d;
+
+/**\class GeomDataAPI_Point2DArray
+ * \ingroup DataModel
+ * \brief Attribute that contains array of 2D point coordinates.
+ */
+
+class GeomDataAPI_Point2DArray : public ModelAPI_Attribute
+{
+public:
+  /// Copy values from another array
+  /// \return \c true if the copy was successful
+  GEOMDATAAPI_EXPORT virtual bool assign(std::shared_ptr<GeomDataAPI_Point2DArray> theOther) = 0;
+
+  /// Returns the size of the array (zero means that it is empty)
+  GEOMDATAAPI_EXPORT virtual int size() = 0;
+
+  /// Sets the new size of the array. The previous data is erased.
+  GEOMDATAAPI_EXPORT virtual void setSize(const int theSize) = 0;
+
+  /// Defines the value of the array by index [0; size-1]
+  GEOMDATAAPI_EXPORT virtual void setPnt(const int theIndex,
+                                         const double theX, const double theY) = 0;
+
+  /// Defines the value of the array by index [0; size-1]
+  GEOMDATAAPI_EXPORT virtual void setPnt(const int theIndex,
+                                         const std::shared_ptr<GeomAPI_Pnt2d>& thePoint) = 0;
+
+  /// Returns the value by the index
+  GEOMDATAAPI_EXPORT virtual std::shared_ptr<GeomAPI_Pnt2d> pnt(const int theIndex) = 0;
+
+  /// Returns the type of this class of attributes
+  static std::string typeId()
+  {
+    return std::string("Point2DArray");
+  }
+
+  /// Returns the type of this class of attributes, not static method
+  GEOMDATAAPI_EXPORT virtual std::string attributeType();
+
+protected:
+  /// Objects are created for features automatically
+  GEOMDATAAPI_EXPORT GeomDataAPI_Point2DArray();
+  GEOMDATAAPI_EXPORT virtual ~GeomDataAPI_Point2DArray();
+};
+
+typedef std::shared_ptr<GeomDataAPI_Point2DArray> AttributePoint2DArrayPtr;
+
+#endif
index db780eac7da4aa4477ff09c591ac2eceaeb68947..5ce42aef320496eaaeb042ad1a6d79f22b616b7e 100644 (file)
 
 void Model_AttributeRefAttrList::append(ObjectPtr theObject)
 {
-  std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
-  myRef->Append(aData->label().Father());  // store label of the object
+  TDF_Label aLabel;
+  if (theObject) {
+    std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
+    aLabel = aData->label().Father();
+  }
+
+  myRef->Append(aLabel); // store label of the object
   myIDs->Append(""); // for the object store an empty string
   // do it before the transaction finish to make just created/removed objects know dependencies
   // and reference from composite feature is removed automatically
@@ -306,7 +311,9 @@ void Model_AttributeRefAttrList::remove(const std::set<int>& theIndices)
         myIDs->Append(anIDIter.Value());
       } else { // found, so need to update the dependencies
         aOneisDeleted = true;
-        ObjectPtr anObj = aDoc->objects()->object(aRefIter.Value());
+        ObjectPtr anObj;
+        if (!aRefIter.Value().IsNull())
+          anObj = aDoc->objects()->object(aRefIter.Value());
         if (anObj.get()) {
           REMOVE_BACK_REF(anObj);
         }
index e5641930e1b1253ab05e0a83f5afbd1ab8c34137..2a25c5136913462dd8887e5249277880e80ac42a 100644 (file)
 
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
 
 #include <GeomData_Point.h>
 #include <GeomData_Point2D.h>
+#include <GeomData_Point2DArray.h>
 #include <GeomData_Dir.h>
 #include <Events_Loop.h>
 #include <Events_InfoMessage.h>
@@ -217,7 +219,10 @@ AttributePtr Model_Data::addAttribute(
     }
     anAttribute->myIsInitialized = anAllInitialized;
     anAttr = anAttribute;
+  } else if (theAttrType == GeomData_Point2DArray::typeId()) {
+    anAttr = new GeomData_Point2DArray(anAttrLab);
   }
+
   if (anAttr) {
     aResult = std::shared_ptr<ModelAPI_Attribute>(anAttr);
     myAttrs[theID] = std::pair<AttributePtr, int>(aResult, anAttrIndex);
index f1bcd1e26707e11949f962c8a4b94f87c7236da8..92474383c6e743179f0c96e25b445fe2cfa95977 100644 (file)
@@ -335,10 +335,12 @@ void ModelAPI_ObjectMovedMessage::setMovedObject(const ObjectPtr& theMovedObject
   myMovedAttribute = AttributePtr();
 }
 
-void ModelAPI_ObjectMovedMessage::setMovedAttribute(const AttributePtr& theMovedAttribute)
+void ModelAPI_ObjectMovedMessage::setMovedAttribute(const AttributePtr& theMovedAttribute,
+                                                    const int thePointIndex)
 {
   myMovedAttribute = theMovedAttribute;
   myMovedObject = ObjectPtr();
+  myMovedPointIndex = thePointIndex;
 }
 
 void ModelAPI_ObjectMovedMessage::setOriginalPosition(double theX, double theY)
index 0b250ebd53e24493c8f0b4b93e42841d71b53aa4..02fdadb0936d97a68e6167a9aa5e4476b4364ac1 100644 (file)
@@ -486,6 +486,7 @@ class ModelAPI_ObjectMovedMessage : public Events_Message
 {
   ObjectPtr myMovedObject;
   AttributePtr myMovedAttribute;
+  int myMovedPointIndex;
 
   std::shared_ptr<GeomAPI_Pnt2d> myOriginalPosition;
   std::shared_ptr<GeomAPI_Pnt2d> myCurrentPosition;
@@ -496,7 +497,10 @@ public:
   /// Set object which is being moved (if the message already contains attribute it will be cleared)
   MODELAPI_EXPORT void setMovedObject(const ObjectPtr& theMovedObject);
   /// Set attribute which is being moved (if the message already contains object it will be cleared)
-  MODELAPI_EXPORT void setMovedAttribute(const AttributePtr& theMovedAttribute);
+  /// \param[in] theMovedAttribute moved attribute
+  /// \param[in] thePointIndex     index of the point if the moved attribute is an array of points
+  MODELAPI_EXPORT void setMovedAttribute(const AttributePtr& theMovedAttribute,
+                                         const int thePointIndex = -1);
 
   /// Return moved object
   ObjectPtr movedObject() const
@@ -504,6 +508,9 @@ public:
   /// Return moved attribute
   AttributePtr movedAttribute() const
   { return myMovedAttribute; }
+  /// Return index of the moved point
+  int movedPointIndex() const
+  { return myMovedPointIndex; }
 
   /// Set original mouse position
   MODELAPI_EXPORT void setOriginalPosition(double theX, double theY);
index 83789b24f3b56cca7f72f5401121995d3fa231ec..0384951d615424e71366c2549568d8b26b301bdd 100644 (file)
@@ -59,8 +59,9 @@ SET(PROJECT_HEADERS
     PartSet_WidgetSketchLabel.h
     PartSet_CenterPrs.h
     PartSet_ExternalPointsMgr.h
-       PartSet_TreeNodes.h
-       PartSet_FieldStepPrs.h
+    PartSet_TreeNodes.h
+    PartSet_FieldStepPrs.h
+    PartSet_WidgetBSplinePoints.h
 )
 
 SET(PROJECT_MOC_HEADERS
@@ -78,6 +79,7 @@ SET(PROJECT_MOC_HEADERS
     PartSet_WidgetShapeSelector.h
     PartSet_WidgetSketchCreator.h
     PartSet_WidgetSketchLabel.h
+    PartSet_WidgetBSplinePoints.h
     PartSet_ExternalPointsMgr.h
 )
 
@@ -109,8 +111,9 @@ SET(PROJECT_SOURCES
     PartSet_WidgetSketchLabel.cpp
     PartSet_CenterPrs.cpp
     PartSet_ExternalPointsMgr.cpp
-       PartSet_TreeNodes.cpp
-       PartSet_FieldStepPrs.cpp
+    PartSet_TreeNodes.cpp
+    PartSet_FieldStepPrs.cpp
+    PartSet_WidgetBSplinePoints.cpp
 )
 
 SET(PROJECT_RESOURCES
index 5b50689714efd32cde8bd4584cae4d8411858834..9c70d7e9f02a223b74336a442183ba25a1d7e369 100644 (file)
@@ -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"
@@ -915,6 +916,12 @@ ModuleBase_ModelWidget* PartSet_Module::createWidgetByType(const std::string& th
     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") {
index fbb50228faf57290a384d347d72b2e8b0b0dffec..759f45bea6ed3033a55547c411e4d812f83f7c45 100644 (file)
@@ -483,6 +483,24 @@ std::shared_ptr<GeomAPI_Pnt2d> PartSet_Tools::getPnt2d(QMouseEvent* theEvent,
   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)
 {
index 7f1c236abb474dc25a51394062dce820cc262cfe..742de4f59f7dde2a3f69499a095ded1da7d2e605 100644 (file)
@@ -215,7 +215,7 @@ public:
 
   /**
   * 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
   */
@@ -223,6 +223,16 @@ public:
                                                  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
diff --git a/src/PartSet/PartSet_WidgetBSplinePoints.cpp b/src/PartSet/PartSet_WidgetBSplinePoints.cpp
new file mode 100644 (file)
index 0000000..5050b33
--- /dev/null
@@ -0,0 +1,641 @@
+// Copyright (C) 2019-2020  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 <PartSet_WidgetBSplinePoints.h>
+
+#include <PartSet_CenterPrs.h>
+#include <PartSet_ExternalObjectsMgr.h>
+#include <PartSet_Module.h>
+#include <PartSet_SketcherReentrantMgr.h>
+#include <PartSet_WidgetPoint2d.h>
+
+#include <XGUI_Tools.h>
+#include <XGUI_Workshop.h>
+#include <XGUI_Displayer.h>
+
+#include <ModuleBase_ISelection.h>
+#include <ModuleBase_IViewer.h>
+#include <ModuleBase_IViewWindow.h>
+#include <ModuleBase_LabelValue.h>
+#include <ModuleBase_Tools.h>
+#include <ModuleBase_ViewerPrs.h>
+#include <ModuleBase_WidgetValidator.h>
+#include <ModuleBase_WidgetValidated.h>
+
+#include <Config_Keywords.h>
+#include <Config_WidgetAPI.h>
+
+#include <Events_Loop.h>
+
+#include <ModelAPI_Events.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_CompositeFeature.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <SketchPlugin_ConstraintCoincidence.h>
+
+#include <QGridLayout>
+#include <QGroupBox>
+#include <QMouseEvent>
+
+static const double MaxCoordinate = 1e12;
+
+PartSet_WidgetBSplinePoints::PartSet_WidgetBSplinePoints(QWidget* theParent,
+                                             ModuleBase_IWorkshop* theWorkshop,
+                                             const Config_WidgetAPI* theData)
+: ModuleBase_ModelWidget(theParent, theData), myWorkshop(theWorkshop),
+  myValueIsCashed(false), myIsFeatureVisibleInCash(true),
+  myXValueInCash(0), myYValueInCash(0),
+  myPointIndex(0), myFinished(false)
+{
+  myRefAttribute = theData->getProperty("reference_attribute");
+
+  // the control should accept the focus, so the boolean flag is corrected to be true
+  myIsObligatory = true;
+  QString aPageName = translate(theData->getProperty(CONTAINER_PAGE_NAME));
+  myGroupBox = new QGroupBox(aPageName, theParent);
+  myGroupBox->setFlat(false);
+
+  bool aAcceptVariables = theData->getBooleanAttribute(DOUBLE_WDG_ACCEPT_EXPRESSIONS, true);
+
+  // B-spline weights attribute
+  myWeightsAttr = theData->getProperty("weights");
+
+  QGridLayout* aGroupLay = new QGridLayout(myGroupBox);
+  ModuleBase_Tools::adjustMargins(aGroupLay);
+  aGroupLay->setSpacing(4);
+  aGroupLay->setColumnStretch(1, 1);
+  createNextPoint();
+
+  QVBoxLayout* aLayout = new QVBoxLayout(this);
+  ModuleBase_Tools::zeroMargins(aLayout);
+  aLayout->addWidget(myGroupBox);
+  setLayout(aLayout);
+
+  myWidgetValidator = new ModuleBase_WidgetValidator(this, myWorkshop);
+  myExternalObjectMgr = new PartSet_ExternalObjectsMgr(theData->getProperty("use_external"),
+                                         theData->getProperty("can_create_external"), true);
+}
+
+void PartSet_WidgetBSplinePoints::createNextPoint()
+{
+  storeCurentValue();
+
+  QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+  int row = (int)(myXSpin.size() + myWeightSpin.size());
+
+  QString aPoleStr = tr("Pole %1");
+  aPoleStr = aPoleStr.arg(myXSpin.size() + 1);
+
+  QGroupBox* aPoleGroupBox = new QGroupBox(aPoleStr, myGroupBox);
+  QGridLayout* aPoleLay = new QGridLayout(aPoleGroupBox);
+  ModuleBase_Tools::adjustMargins(aPoleLay);
+  aPoleLay->setSpacing(2);
+  aPoleLay->setColumnStretch(1, 1);
+
+  myXSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("X")));
+  aPoleLay->addWidget(myXSpin.back(), 0, 1);
+  myYSpin.push_back(new ModuleBase_LabelValue(aPoleGroupBox, tr("Y")));
+  aPoleLay->addWidget(myYSpin.back(), 1, 1);
+
+  aGroupLay->addWidget(aPoleGroupBox, row, 1);
+
+  QString aWeightStr = tr("Weight %1");
+  aWeightStr = aWeightStr.arg(myWeightSpin.size() + 1);
+
+  myWeightSpin.push_back(new ModuleBase_LabelValue(myGroupBox, aWeightStr));
+  aGroupLay->addWidget(myWeightSpin.back(), ++row, 1);
+}
+
+void PartSet_WidgetBSplinePoints::removeLastPoint()
+{
+  QGridLayout* aGroupLay = dynamic_cast<QGridLayout*>(myGroupBox->layout());
+  aGroupLay->removeWidget(myWeightSpin.back());
+  myWeightSpin.pop_back();
+  aGroupLay->removeWidget(myYSpin.back());
+  aGroupLay->removeWidget(myXSpin.back());
+  aGroupLay->removeWidget(myXSpin.back()->parentWidget());
+  myYSpin.pop_back();
+  myXSpin.pop_back();
+
+  // update B-spline feature attributes
+  storeValueCustom();
+}
+
+bool PartSet_WidgetBSplinePoints::isValidSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
+{
+  bool aValid = true;
+
+  PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+  if (aModule->sketchReentranceMgr()->isInternalEditActive())
+    return true; // when internal edit is started a new feature is created. I has not results, AIS
+
+  // the selection is not possible if the current feature has no presentation for the current
+  // attribute not in AIS not in results. If so, no object in current feature where make
+  // coincidence, so selection is not necessary
+  GeomShapePtr anAISShape;
+  GeomPresentablePtr aPrs = std::dynamic_pointer_cast<GeomAPI_IPresentable>(myFeature);
+  if (aPrs.get()) {
+    AISObjectPtr anAIS;
+    anAIS = aPrs->getAISObject(anAIS);
+    if (anAIS.get()) {
+      anAISShape = anAIS->getShape();
+    }
+  }
+  const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = myFeature->results();
+  if (!anAISShape.get() && aResults.empty())
+    return true;
+
+  AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+  if (aRefAttrList)
+    return isValidSelectionForAttribute_(theValue, myFeature->attribute(attributeID()));
+  return true;
+}
+
+bool PartSet_WidgetBSplinePoints::isValidSelectionForAttribute_(
+                                            const ModuleBase_ViewerPrsPtr& theValue,
+                                            const AttributePtr& theAttribute)
+{
+  bool aValid = false;
+
+  // stores the current values of the widget attribute
+  bool isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked;
+
+  AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+  ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, true,
+      isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
+  myWidgetValidator->storeAttributeValue(aRefAttrList);
+
+  // saves the owner value to the widget attribute
+  aValid = setSelectionCustom(theValue);
+  if (aValid)
+    // checks the attribute validity
+    aValid = myWidgetValidator->isValidAttribute(theAttribute);
+
+  // restores the current values of the widget attribute
+  myWidgetValidator->restoreAttributeValue(aRefAttrList, aValid);
+  myExternalObjectMgr->removeExternal(sketch(), myFeature, myWorkshop, true);
+
+  ModuleBase_WidgetValidated::blockFeatureAttribute(aRefAttrList, myFeature, false,
+      isFlushesActived, isAttributeSetInitializedBlocked, isAttributeSendUpdatedBlocked);
+  return aValid;
+}
+
+bool PartSet_WidgetBSplinePoints::setSelectionCustom(const ModuleBase_ViewerPrsPtr& theValue)
+{
+  bool isDone = false;
+  GeomShapePtr aShape = theValue->shape();
+  if (aShape.get() && !aShape->isNull()) {
+    Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
+    const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
+    GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+    if (aPnt) {
+      fillRefAttribute(aPnt, theValue);
+      isDone = true;
+    }
+    else if (aTDShape.ShapeType() == TopAbs_EDGE) {
+      fillRefAttribute(theValue);
+      isDone = true;
+    }
+  }
+  return isDone;
+}
+
+static void fillLabels(std::vector<ModuleBase_LabelValue*>& theLabels, const double theValue)
+{
+  for (std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
+       anIt != theLabels.end(); ++anIt)
+    (*anIt)->setValue(theValue);
+}
+
+bool PartSet_WidgetBSplinePoints::resetCustom()
+{
+  bool aDone = false;
+  if (!isUseReset() || isComputedDefault())
+    aDone = false;
+  else {
+    if (myValueIsCashed) {
+      // if the restored value should be hidden, aDone = true to set
+      // reset state for the widget in the parent
+      aDone = restoreCurentValue();
+      emit objectUpdated();
+    }
+    else {
+      // it is important to block the spin box control in order to do not through out the
+      // locking of the validating state.
+      fillLabels(myXSpin, 0.0);
+      fillLabels(myYSpin, 0.0);
+      fillLabels(myWeightSpin, 1.0);
+
+      storeValueCustom();
+      aDone = true;
+    }
+  }
+  return aDone;
+}
+
+PartSet_WidgetBSplinePoints::~PartSet_WidgetBSplinePoints()
+{
+  delete myExternalObjectMgr;
+}
+
+bool PartSet_WidgetBSplinePoints::setPoint(double theX, double theY)
+{
+  if (fabs(theX) >= MaxCoordinate || fabs(theY) >= MaxCoordinate)
+    return false;
+
+  myXSpin.back()->setValue(theX);
+  myYSpin.back()->setValue(theY);
+  myWeightSpin.back()->setValue(1.0);
+
+  storeValue();
+  return true;
+}
+
+void PartSet_WidgetBSplinePoints::storePolesAndWeights() const
+{
+  std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+  AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+      aData->attribute(attributeID()));
+  AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+  aPointArray->setSize((int)myXSpin.size());
+  aWeightsArray->setSize((int)myWeightSpin.size());
+
+  std::vector<ModuleBase_LabelValue*>::const_iterator aXIt = myXSpin.begin();
+  std::vector<ModuleBase_LabelValue*>::const_iterator aYIt = myYSpin.begin();
+  for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end(); ++anIndex, ++aXIt, ++aYIt)
+    aPointArray->setPnt(anIndex, (*aXIt)->value(), (*aYIt)->value());
+
+  std::vector<ModuleBase_LabelValue*>::const_iterator aWIt = myWeightSpin.begin();
+  for (int anIndex = 0; aWIt != myWeightSpin.end(); ++anIndex, ++aWIt)
+    aWeightsArray->setValue(anIndex, (*aWIt)->value());
+}
+
+bool PartSet_WidgetBSplinePoints::storeValueCustom()
+{
+  std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+  if (!aData || !aData->isValid()) // can be on abort of sketcher element
+    return false;
+  AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+      aData->attribute(attributeID()));
+  AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+  PartSet_WidgetBSplinePoints* that = (PartSet_WidgetBSplinePoints*) this;
+  bool isBlocked = that->blockSignals(true);
+  bool isImmutable = aPointArray->setImmutable(true);
+
+  if (myFeature->isMacro()) {
+    // Moving points of macro-features has been processed directly (without solver)
+    storePolesAndWeights();
+    updateObject(myFeature);
+
+  } else {
+    if (!aPointArray->isInitialized()) {
+      storePolesAndWeights();
+    }
+
+    std::shared_ptr<ModelAPI_ObjectMovedMessage> aMessage(
+        new ModelAPI_ObjectMovedMessage(this));
+    aMessage->setMovedAttribute(aPointArray, aPointArray->size() - 1);
+    aMessage->setOriginalPosition(aPointArray->pnt(aPointArray->size() - 1));
+    aMessage->setCurrentPosition(myXSpin.back()->value(), myYSpin.back()->value());
+    Events_Loop::loop()->send(aMessage);
+  }
+
+  aPointArray->setImmutable(isImmutable);
+  that->blockSignals(isBlocked);
+
+  return true;
+}
+
+bool PartSet_WidgetBSplinePoints::restoreValueCustom()
+{
+  std::shared_ptr<ModelAPI_Data> aData = myFeature->data();
+  AttributePoint2DArrayPtr aPointArray = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+      aData->attribute(attributeID()));
+  AttributeDoubleArrayPtr aWeightsArray = aData->realArray(myWeightsAttr);
+
+  if (aPointArray->isInitialized()) {
+    while (myXSpin.size() < aPointArray->size())
+      createNextPoint();
+
+    std::vector<ModuleBase_LabelValue*>::iterator aXIt = myXSpin.begin();
+    std::vector<ModuleBase_LabelValue*>::iterator aYIt = myYSpin.begin();
+    for (int anIndex = 0; aXIt != myXSpin.end() && aYIt != myYSpin.end();
+         ++anIndex, ++aXIt, ++aYIt) {
+      GeomPnt2dPtr aPoint = aPointArray->pnt(anIndex);
+      (*aXIt)->setValue(aPoint->x());
+      (*aYIt)->setValue(aPoint->y());
+    }
+
+    std::vector<ModuleBase_LabelValue*>::iterator aWIt = myWeightSpin.begin();
+    for (int anIndex = 0; aWIt != myWeightSpin.end(); ++anIndex, ++aWIt)
+      (*aWIt)->setValue(aWeightsArray->value(anIndex));
+  }
+  else {
+    if (myXSpin.empty())
+      createNextPoint();
+
+    myXSpin.back()->setValue(0.0);
+    myYSpin.back()->setValue(0.0);
+    myWeightSpin.back()->setValue(0.0);
+  }
+
+  return true;
+}
+
+static void storeArray(const std::vector<ModuleBase_LabelValue*>& theLabels,
+                       std::vector<double>& theValues)
+{
+  theValues.clear();
+  theValues.reserve(theLabels.size());
+  for (std::vector<ModuleBase_LabelValue*>::const_iterator anIt = theLabels.begin();
+       anIt != theLabels.end(); ++anIt)
+    theValues.push_back((*anIt)->value());
+}
+
+void PartSet_WidgetBSplinePoints::storeCurentValue()
+{
+  myValueIsCashed = true;
+  myIsFeatureVisibleInCash = XGUI_Displayer::isVisible(
+                       XGUI_Tools::workshop(myWorkshop)->displayer(), myFeature);
+
+  storeArray(myXSpin, myXValueInCash);
+  storeArray(myYSpin, myYValueInCash);
+  storeArray(myWeightSpin, myWeightInCash);
+}
+
+static void restoreArray(std::vector<double>& theCacheValues,
+                         std::vector<ModuleBase_LabelValue*>& theLabels)
+{
+  std::vector<double>::iterator aCIt = theCacheValues.begin();
+  std::vector<ModuleBase_LabelValue*>::iterator anIt = theLabels.begin();
+  for (; anIt != theLabels.end(); ++anIt) {
+    if (aCIt != theCacheValues.end())
+      (*anIt)->setValue(*aCIt++);
+    else
+      (*anIt)->setValue(0.0);
+  }
+  theCacheValues.clear();
+}
+
+bool PartSet_WidgetBSplinePoints::restoreCurentValue()
+{
+  bool aRestoredAndHidden = true;
+
+  bool isVisible = myIsFeatureVisibleInCash;
+
+  myValueIsCashed = false;
+  myIsFeatureVisibleInCash = true;
+  // fill the control widgets by the cashed value
+  restoreArray(myXValueInCash, myXSpin);
+  restoreArray(myYValueInCash, myYSpin);
+  restoreArray(myWeightInCash, myWeightSpin);
+
+  // store value to the model
+  storeValueCustom();
+  if (isVisible) {
+    setValueState(Stored);
+    aRestoredAndHidden = false;
+  }
+  else
+    aRestoredAndHidden = true;
+
+  return aRestoredAndHidden;
+}
+
+QList<QWidget*> PartSet_WidgetBSplinePoints::getControls() const
+{
+  QList<QWidget*> aControls;
+  std::vector<ModuleBase_LabelValue*>::const_iterator aXIt = myXSpin.begin();
+  std::vector<ModuleBase_LabelValue*>::const_iterator aYIt = myYSpin.begin();
+  std::vector<ModuleBase_LabelValue*>::const_iterator aWIt = myWeightSpin.begin();
+  for (; aXIt != myXSpin.end() && aYIt != myYSpin.end() && aWIt != myWeightSpin.end();
+       ++aXIt, ++aYIt, ++aWIt) {
+    aControls.append(*aXIt);
+    aControls.append(*aYIt);
+    aControls.append(*aWIt);
+  }
+  return aControls;
+}
+
+void PartSet_WidgetBSplinePoints::selectionModes(int& theModuleSelectionModes, QIntList& theModes)
+{
+  theModuleSelectionModes = -1;
+  theModes << TopAbs_VERTEX;
+  theModes << TopAbs_EDGE;
+}
+
+void PartSet_WidgetBSplinePoints::deactivate()
+{
+  // the value of the control should be stored to model if it was not
+  // initialized yet. It is important when we leave this control by Tab key.
+  // It should not be performed by the widget activation as the preview
+  // is visualized with default value. Line point is moved to origin.
+  AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
+  if (anAttribute && !anAttribute->isInitialized())
+    storeValue();
+
+  ModuleBase_ModelWidget::deactivate();
+}
+
+void PartSet_WidgetBSplinePoints::mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent)
+{
+  // the contex menu release by the right button should not be processed by this widget
+  if (theEvent->button() != Qt::LeftButton)
+    return;
+
+  ModuleBase_ISelection* aSelection = myWorkshop->selection();
+  Handle(V3d_View) aView = theWindow->v3dView();
+
+  QList<ModuleBase_ViewerPrsPtr> aList = aSelection->getSelected(ModuleBase_ISelection::Viewer);
+  ModuleBase_ViewerPrsPtr aFirstValue =
+    aList.size() > 0 ? aList.first() : ModuleBase_ViewerPrsPtr();
+  if (!aFirstValue.get() && myPreSelected.get()) {
+    aFirstValue = myPreSelected;
+  }
+
+  TopoDS_Shape aSelectedShape;
+  ObjectPtr aSelectedObject;
+
+  // if we have selection and use it
+  if (aFirstValue.get() && isValidSelectionCustom(aFirstValue) &&
+      aFirstValue->shape().get()) { // Trihedron Axis may be selected, but shape is empty
+    GeomShapePtr aGeomShape = aFirstValue->shape();
+    aSelectedShape = aGeomShape->impl<TopoDS_Shape>();
+    aSelectedObject = aFirstValue->object();
+
+    FeaturePtr aSelectedFeature = ModelAPI_Feature::feature(aSelectedObject);
+    std::shared_ptr<SketchPlugin_Feature> aSPFeature;
+    if (aSelectedFeature.get())
+      aSPFeature = std::dynamic_pointer_cast<SketchPlugin_Feature>(aSelectedFeature);
+
+    bool isSketchExternalFeature = aSPFeature.get() && aSPFeature->isExternal();
+    if ((!aSPFeature && !aSelectedShape.IsNull()) || isSketchExternalFeature) {
+      ObjectPtr aFixedObject =
+          PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aSelectedObject, mySketch);
+      if (aFixedObject)
+        aSelectedObject = aFixedObject;
+      else if (!isSketchExternalFeature) {
+        FeaturePtr aCreatedFeature;
+        aSelectedObject = PartSet_Tools::createFixedObjectByExternal(
+            aGeomShape, aSelectedObject, mySketch, false, aCreatedFeature);
+      }
+    }
+  }
+  // The selection could be a center of an external circular object
+  else if (aFirstValue.get() && (!aFirstValue->interactive().IsNull())) {
+    Handle(PartSet_CenterPrs) aAIS =
+        Handle(PartSet_CenterPrs)::DownCast(aFirstValue->interactive());
+    if (!aAIS.IsNull()) {
+      gp_Pnt aPntComp = aAIS->Component()->Pnt();
+      GeomVertexPtr aVertPtr(new GeomAPI_Vertex(aPntComp.X(), aPntComp.Y(), aPntComp.Z()));
+      aSelectedShape = aVertPtr->impl<TopoDS_Shape>();
+
+      aSelectedObject =
+          PartSet_Tools::findFixedObjectByExternal(aSelectedShape, aAIS->object(), mySketch);
+      if (!aSelectedObject.get())
+      {
+        FeaturePtr aCreatedFeature;
+        aSelectedObject = PartSet_Tools::createFixedByExternalCenter(aAIS->object(), aAIS->edge(),
+            aAIS->centerType(), mySketch, false, aCreatedFeature);
+      }
+    }
+  }
+
+  GeomPnt2dPtr aSelectedPoint = PartSet_Tools::getPnt2d(aView, aSelectedShape, mySketch);
+  if (aSelectedPoint) {
+    // nullify selected object to add reference to attribute instead of its owner
+    aSelectedObject = ObjectPtr();
+  }
+  else {
+    aSelectedPoint = PartSet_Tools::getPnt2d(theEvent, theWindow, mySketch);
+    setValueState(Stored); // in case of edge selection, Apply state should also be updated
+  }
+  if (aSelectedObject)
+    fillRefAttribute(aSelectedObject);
+  else
+    fillRefAttribute(aSelectedPoint, aFirstValue);
+
+  // next pole of B-spline
+  createNextPoint();
+}
+
+void PartSet_WidgetBSplinePoints::mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent)
+{
+  PartSet_Module* aModule = dynamic_cast<PartSet_Module*>(myWorkshop->module());
+
+  if (myFinished || isEditingMode() || aModule->sketchReentranceMgr()->isInternalEditActive())
+    return;
+
+  gp_Pnt aPoint = PartSet_Tools::convertClickToPoint(theEvent->pos(), theWindow->v3dView());
+
+  double aX = 0, aY = 0;
+  PartSet_Tools::convertTo2D(aPoint, mySketch, theWindow->v3dView(), aX, aY);
+  if (myState != ModifiedInViewer)
+    storeCurentValue();
+  // we need to block the value state change
+  bool isBlocked = blockValueState(true);
+  setPoint(aX, aY);
+  blockValueState(isBlocked);
+  setValueState(ModifiedInViewer);
+}
+
+bool PartSet_WidgetBSplinePoints::processEscape()
+{
+  bool isProcessed = !isEditingMode();
+  if (isProcessed) {
+    // remove widgets corrsponding to the last pole/weight of B-spline
+    removeLastPoint();
+    myFinished = true;
+
+    emit focusOutWidget(this);
+  }
+  return isProcessed;
+}
+
+bool PartSet_WidgetBSplinePoints::useSelectedShapes() const
+{
+  return true;
+}
+
+AttributeRefAttrListPtr PartSet_WidgetBSplinePoints::attributeRefAttrList() const
+{
+  if (myRefAttribute.empty())
+    return AttributeRefAttrListPtr();
+
+  AttributePtr anAttributeRef = feature()->attribute(myRefAttribute);
+  if (!anAttributeRef.get())
+    return AttributeRefAttrListPtr();
+
+  return std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(anAttributeRef);
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(GeomPnt2dPtr theClickedPoint,
+                              const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
+{
+  AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+  if (!aRefAttrList.get())
+    return;
+
+  FeaturePtr aFeature = feature();
+  std::string anAttribute = attributeID();
+
+  if (aFeature.get()) {
+    AttributePoint2DPtr aClickedFeaturePoint =
+        PartSet_WidgetPoint2D::findFirstEqualPointInSketch(mySketch, aFeature, theClickedPoint);
+    if (aClickedFeaturePoint.get())
+      aRefAttrList->append(aClickedFeaturePoint);
+    else
+      fillRefAttribute(theValue);
+  }
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(const ModuleBase_ViewerPrsPtr& theValue)
+{
+  ObjectPtr anObject;
+  if (theValue)
+    anObject = getGeomSelection(theValue);
+  fillRefAttribute(anObject);
+}
+
+void PartSet_WidgetBSplinePoints::fillRefAttribute(const ObjectPtr& theObject)
+{
+  AttributeRefAttrListPtr aRefAttrList = attributeRefAttrList();
+  if (aRefAttrList.get())
+    aRefAttrList->append(theObject);
+}
+
+ObjectPtr PartSet_WidgetBSplinePoints::getGeomSelection(const ModuleBase_ViewerPrsPtr& theValue)
+{
+  ObjectPtr anObject;
+  GeomShapePtr aShape;
+  ModuleBase_ISelection* aSelection = myWorkshop->selection();
+  anObject = aSelection->getResult(theValue);
+  aShape = aSelection->getShape(theValue);
+  myExternalObjectMgr->getGeomSelection(theValue, anObject, aShape, myWorkshop, sketch(), true);
+
+  return anObject;
+}
diff --git a/src/PartSet/PartSet_WidgetBSplinePoints.h b/src/PartSet/PartSet_WidgetBSplinePoints.h
new file mode 100644 (file)
index 0000000..f537dc8
--- /dev/null
@@ -0,0 +1,188 @@
+// Copyright (C) 2019-2020  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 PartSet_WidgetBSplinePoints_H
+#define PartSet_WidgetBSplinePoints_H
+
+#include "PartSet.h"
+#include "PartSet_MouseProcessor.h"
+
+#include <ModuleBase_ModelWidget.h>
+
+#include <QObject>
+
+class GeomAPI_Pnt2d;
+class ModelAPI_CompositeFeature;
+class ModuleBase_LabelValue;
+class PartSet_ExternalObjectsMgr;
+class QGroupBox;
+
+/**\class PartSet_WidgetBSplinePoints
+ * \ingroup Modules
+ * \brief Implementation of model widget to provide widget to input a list of 2D poles
+ *        of B-spline curve in association with weights
+ * In XML can be defined as following:
+ * \code
+ * <sketch-bspline_selector id="poles" weights="weights"/>
+ * \endcode
+ */
+class PARTSET_EXPORT PartSet_WidgetBSplinePoints : public ModuleBase_ModelWidget,
+                                                   public PartSet_MouseProcessor
+{
+Q_OBJECT
+public:
+  /// Constructor
+  /// \param theParent the parent object
+  /// \param theWorkshop a current workshop
+  /// \param theData the widget configuation. The attribute of the model widget is obtained from
+  PartSet_WidgetBSplinePoints(QWidget* theParent, ModuleBase_IWorkshop* theWorkshop,
+                              const Config_WidgetAPI* theData);
+  /// Destructor
+  virtual ~PartSet_WidgetBSplinePoints();
+
+  /// Fills given container with selection modes if the widget has it
+  /// \param [out] theModuleSelectionModes module additional modes, -1 means all default modes
+  /// \param theModes [out] a container of modes
+  virtual void selectionModes(int& theModuleSelectionModes, QIntList& theModes);
+
+  /// Checks if the selection presentation is valid in widget
+  /// \param theValue a selected presentation in the view
+  /// \return a boolean value
+  virtual bool isValidSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+  /// Checks all attribute validators returns valid. It tries on the given selection
+  /// to current attribute by setting the value inside and calling validators. After this,
+  /// the previous attribute value is restored.The valid/invalid value is cashed.
+  /// \param theValue a selected presentation in the view
+  /// \param theAttribute the attribute
+  /// \return a boolean value
+  bool isValidSelectionForAttribute_(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue,
+                                     const std::shared_ptr<ModelAPI_Attribute>& theAttribute);
+
+  /// Fills the attribute with the value of the selected owner
+  /// \param thePrs a selected owner
+  bool setSelectionCustom(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+  /// Returns list of widget controls
+  /// \return a control list
+  virtual QList<QWidget*> getControls() const;
+
+  /// The methiod called when widget is deactivated
+  virtual void deactivate();
+
+  /// \returns the sketch instance
+  std::shared_ptr<ModelAPI_CompositeFeature> sketch() const { return mySketch; }
+
+  /// Set sketch instance
+  void setSketch(std::shared_ptr<ModelAPI_CompositeFeature> theSketch) { mySketch = theSketch; }
+
+  /// Fill the widget values by given point
+  /// \param theX the X coordinate
+  /// \param theY the Y coordinate
+  /// \returns True in case of success
+  bool setPoint(double theX, double theY);
+
+  /// Returns true if the event is processed.
+  virtual bool processEscape();
+
+  /// Returns true if the attribute can be changed using the selected shapes in the viewer
+  /// and creating a coincidence constraint to them. This control use them.
+  virtual bool useSelectedShapes() const;
+
+  /// Processing the mouse move event in the viewer
+  /// \param theWindow a view window
+  /// \param theEvent a mouse event
+  virtual void mouseMoved(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
+
+  /// Processing the mouse release event in the viewer
+  /// \param theWindow a view window
+  /// \param theEvent a mouse event
+  virtual void mouseReleased(ModuleBase_IViewWindow* theWindow, QMouseEvent* theEvent);
+
+protected:
+  /// Saves the internal parameters to the given feature
+  /// \return True in success
+  virtual bool storeValueCustom();
+
+  /// Restore value from attribute data to the widget's control
+  virtual bool restoreValueCustom();
+
+  /// Store current value in cashed value
+  void storeCurentValue();
+
+  /// Restore cashed value in the model attribute
+  /// \return boolean state if the restored feature shoud be hidden
+  bool restoreCurentValue();
+
+  /// Fills the widget with default values
+  /// \return true if the widget current value is reset
+  virtual bool resetCustom();
+
+private:
+  /// Create labels for the next B-spline point
+  void createNextPoint();
+  /// Remove labels for the last B-spline point
+  void removeLastPoint();
+
+  /// Save B-spline poles and weights to corresponding attributes
+  void storePolesAndWeights() const;
+
+  /// Returns attribute reference if the key is defined in XML definition of this control
+  /// \return found attribute or null
+  std::shared_ptr<ModelAPI_AttributeRefAttrList> attributeRefAttrList() const;
+
+  void fillRefAttribute(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+  void fillRefAttribute(std::shared_ptr<GeomAPI_Pnt2d> theClickedPoint,
+                        const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+  void fillRefAttribute(const ObjectPtr& theObject);
+
+  ObjectPtr getGeomSelection(const std::shared_ptr<ModuleBase_ViewerPrs>& theValue);
+
+protected:
+  ModuleBase_IWorkshop* myWorkshop; ///< workshop
+
+private:
+  QGroupBox* myGroupBox;  ///< the parent group box for all intenal widgets
+  std::vector<ModuleBase_LabelValue*> myXSpin; ///< the label for the X coordinate
+  std::vector<ModuleBase_LabelValue*> myYSpin; ///< the label for the Y coordinate
+  std::vector<ModuleBase_LabelValue*> myWeightSpin; ///< the label for the weight
+  PartSet_ExternalObjectsMgr* myExternalObjectMgr; ///< reference to external objects manager
+
+  /// value used as selection in mouse release method
+  std::shared_ptr<ModuleBase_ViewerPrs> myPreSelected;
+
+  /// it is important during restart operation
+  CompositeFeaturePtr mySketch;
+
+  std::string myRefAttribute; /// if not empty, coincidences are not set but attribute is filled
+
+  bool myValueIsCashed; /// boolean state if the value is cashed during value state change
+  bool myIsFeatureVisibleInCash; /// boolean value if the feature was visible when cash if filled
+  std::vector<double> myXValueInCash; /// the cashed X value during value state change
+  std::vector<double> myYValueInCash; /// the cashed Y value during value state change
+  std::vector<double> myWeightInCash; /// the cached Weight value during valude state change
+
+  std::string myWeightsAttr;
+
+  int myPointIndex; /// index of the changing point
+
+  bool myFinished; /// \c true if building the B-spline is finished (escape pressed)
+};
+
+#endif
index 8183806b9d66b41da4ca2e03093a3734821a68f8..b01f5fecddd6dfd17c5180c4a86f1b5088766f5e 100644 (file)
@@ -243,10 +243,10 @@ bool PartSet_WidgetPoint2D::setSelectionCustom(const ModuleBase_ViewerPrsPtr& th
   GeomShapePtr aShape = theValue->shape();
   if (aShape.get() && !aShape->isNull()) {
     Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
-    double aX = 0, aY = 0;
     const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
-    if (getPoint2d(aView, aTDShape, aX, aY)) {
-      fillRefAttribute(aX, aY, theValue);
+    GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+    if (aPnt) {
+      fillRefAttribute(aPnt->x(), aPnt->y(), theValue);
       isDone = true;
     }
     else if (aTDShape.ShapeType() == TopAbs_EDGE) {
@@ -306,11 +306,11 @@ bool PartSet_WidgetPoint2D::setSelection(QList<ModuleBase_ViewerPrsPtr>& theValu
     GeomShapePtr aShape = aValue->shape();
     if (aShape.get() && !aShape->isNull()) {
       Handle(V3d_View) aView = myWorkshop->viewer()->activeView();
-      double aX = 0, aY = 0;
       const TopoDS_Shape& aTDShape = aShape->impl<TopoDS_Shape>();
-      if (getPoint2d(aView, aTDShape, aX, aY)) {
-        isDone = setPoint(aX, aY);
-        setConstraintToPoint(aX, aY, aValue);
+      GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aTDShape, mySketch);
+      if (aPnt) {
+        isDone = setPoint(aPnt->x(), aPnt->y());
+        setConstraintToPoint(aPnt->x(), aPnt->y(), aValue);
       }
     }
   }
@@ -476,24 +476,6 @@ void PartSet_WidgetPoint2D::deactivate()
   ModuleBase_ModelWidget::deactivate();
 }
 
-bool PartSet_WidgetPoint2D::getPoint2d(const Handle(V3d_View)& theView,
-                                       const TopoDS_Shape& theShape,
-                                       double& theX, double& theY) const
-{
-  if (!theShape.IsNull()) {
-    if (theShape.ShapeType() == TopAbs_VERTEX) {
-      const TopoDS_Vertex& aVertex = TopoDS::Vertex(theShape);
-      if (!aVertex.IsNull()) {
-        // A case when point is taken from existing vertex
-        gp_Pnt aPoint = BRep_Tool::Pnt(aVertex);
-        PartSet_Tools::convertTo2D(aPoint, mySketch, theView, theX, theY);
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
 bool PartSet_WidgetPoint2D::setConstraintToPoint(double theClickedX, double theClickedY,
                                   const std::shared_ptr<ModuleBase_ViewerPrs>& theValue)
 {
@@ -627,14 +609,19 @@ void PartSet_WidgetPoint2D::mouseReleased(ModuleBase_IViewWindow* theWindow, QMo
       }
     }
     if (anExternal) {
+      GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
       double aX = 0, aY = 0;
-      if (getPoint2d(aView, aShape, aX, aY) && isFeatureContainsPoint(myFeature, aX, aY)) {
+      if (aPnt) {
+        aX = aPnt->x();
+        aY = aPnt->y();
+      }
+      if (aPnt && isFeatureContainsPoint(myFeature, aX, aY)) {
         // do not create a constraint to the point, which already used by the feature
         // if the feature contains the point, focus is not switched
         setPoint(aX, aY);
       }
       else {
-        if (getPoint2d(aView, aShape, aX, aY))
+        if (aPnt)
           setPoint(aX, aY);
         else {
           if (aShape.ShapeType() == TopAbs_EDGE) {
@@ -674,20 +661,23 @@ void PartSet_WidgetPoint2D::mouseReleased(ModuleBase_IViewWindow* theWindow, QMo
       }
     }
     if (!anExternal) {
-      double aX = 0, aY = 0;
       bool isProcessed = false;
-      if (getPoint2d(aView, aShape, aX, aY) && isFeatureContainsPoint(myFeature, aX, aY)) {
+      GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
+      if (aPnt && isFeatureContainsPoint(myFeature, aPnt->x(), aPnt->y())) {
         // when the point is selected, the coordinates of the point should be set into the attribute
         // if the feature contains the point, focus is not switched
-        setPoint(aX, aY);
+        setPoint(aPnt->x(), aPnt->y());
       }
       else {
+        double aX = 0, aY = 0;
         bool anOrphanPoint = isOrphanPoint(aSelectedFeature, mySketch, aX, aY);
         // do not set a coincidence constraint in the attribute if the feature contains a point
         // with the same coordinates. It is important for line creation in order to do not set
         // the same constraints for the same points, oterwise the result line has zero length.
         bool isAuxiliaryFeature = false;
-        if (getPoint2d(aView, aShape, aX, aY)) {
+        if (aPnt) {
+          aX = aPnt->x();
+          aY = aPnt->y();
           setPoint(aX, aY);
           setConstraintToPoint(aX, aY, aFirstValue);
         }
@@ -738,11 +728,11 @@ void PartSet_WidgetPoint2D::mouseReleased(ModuleBase_IViewWindow* theWindow, QMo
       // external objects e.g. selection of trihedron axis when input end arc point
       updateObject(feature());
 
-      double aX = 0, aY = 0;
-      if (getPoint2d(aView, aShape, aX, aY)) {
+      GeomPnt2dPtr aPnt = PartSet_Tools::getPnt2d(aView, aShape, mySketch);
+      if (aPnt) {
         // do not create a constraint to the point, which already used by the feature
         // if the feature contains the point, focus is not switched
-        setPoint(aX, aY);
+        setPoint(aPnt->x(), aPnt->y());
       }
       emit vertexSelected(); // it stops the reentrant operation
       emit focusOutWidget(this);
index 515a03c4120a7856bf950eee829b15285e887757..3a062cfa486b5fddc1e4ebdba079ab31cf76561e 100644 (file)
@@ -211,14 +211,6 @@ protected:
   virtual void initializeValueByActivate();
 
  private:
-   /// Returns point 2d from selected vertex
-   /// \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
-   bool getPoint2d(const Handle(V3d_View)& theView, const TopoDS_Shape& theShape,
-                   double& theX, double& theY) const;
-
    /// Creates constrains of the clicked point
    /// \param theClickedX the horizontal coordnate of the point
    /// \param theClickedY the vertical coordnate of the point
@@ -230,6 +222,7 @@ protected:
    /// \return true if succed
    bool setConstraintToObject(const ObjectPtr& theObject);
 
+public:
    /// Returns if the feature is an orphan point, circle or an arc. Returns true if it
    /// has no a coincident to other lines. It processes point, circle and arc features
    /// In circle an arc features, only centers are processed, for other points, it returns
@@ -274,6 +267,7 @@ protected:
                                        const FeaturePtr& theSkipFeature,
                                        const std::shared_ptr<GeomAPI_Pnt2d>& thePoint);
 
+private:
   /// Returns attribute reference if the key is defined in XML definition of this control
   /// \return found attribute or null
   std::shared_ptr<ModelAPI_AttributeRefAttr> attributeRefAttr() const;
index 10105e1ca14b746b2e1ea8fc1cfdbbc29bd64338..c282d548131921be6031d9192a9cf72f87277d52 100644 (file)
@@ -23,6 +23,7 @@ INCLUDE(UnitTest)
 SET(PROJECT_HEADERS
     SketchPlugin.h
     SketchPlugin_Arc.h
+    SketchPlugin_BSpline.h
     SketchPlugin_Circle.h
     SketchPlugin_Constraint.h
     SketchPlugin_ConstraintAngle.h
@@ -54,6 +55,7 @@ SET(PROJECT_HEADERS
     SketchPlugin_Line.h
     SketchPlugin_MacroArc.h
     SketchPlugin_MacroArcReentrantMessage.h
+    SketchPlugin_MacroBSpline.h
     SketchPlugin_MacroCircle.h
     SketchPlugin_MacroEllipse.h
     SketchPlugin_MacroEllipticArc.h
@@ -73,6 +75,7 @@ SET(PROJECT_HEADERS
 
 SET(PROJECT_SOURCES
     SketchPlugin_Arc.cpp
+    SketchPlugin_BSpline.cpp
     SketchPlugin_Circle.cpp
     SketchPlugin_Constraint.cpp
     SketchPlugin_ConstraintAngle.cpp
@@ -102,6 +105,7 @@ SET(PROJECT_SOURCES
     SketchPlugin_IntersectionPoint.cpp
     SketchPlugin_Line.cpp
     SketchPlugin_MacroArc.cpp
+    SketchPlugin_MacroBSpline.cpp
     SketchPlugin_MacroCircle.cpp
     SketchPlugin_MacroEllipse.cpp
     SketchPlugin_MacroEllipticArc.cpp
diff --git a/src/SketchPlugin/SketchPlugin_BSpline.cpp b/src/SketchPlugin/SketchPlugin_BSpline.cpp
new file mode 100644 (file)
index 0000000..f226e06
--- /dev/null
@@ -0,0 +1,152 @@
+// Copyright (C) 2019-2020  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_BSpline.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+////#include <GeomAPI_Dir2d.h>
+////#include <GeomAPI_Edge.h>
+////#include <GeomAPI_Ellipse.h>
+////#include <GeomAPI_Ellipse2d.h>
+#include <GeomAPI_Pnt2d.h>
+////#include <GeomAPI_XY.h>
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+////#include <cmath>
+////
+////static const double tolerance = 1e-7;
+////static const double paramTolerance = 1.e-4;
+////static const double PI = 3.141592653589793238463;
+
+
+SketchPlugin_BSpline::SketchPlugin_BSpline()
+  : SketchPlugin_SketchEntity()
+{
+}
+
+void SketchPlugin_BSpline::initDerivedClassAttributes()
+{
+  data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
+  data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
+
+  data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+}
+
+void SketchPlugin_BSpline::execute()
+{
+  SketchPlugin_Sketch* aSketch = sketch();
+  if(!aSketch) {
+    return;
+  }
+
+  AttributePoint2DArrayPtr aPolesArray =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+  AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+
+  // convert poles to 3D
+  std::vector<GeomPointPtr> aPoles3D;
+  aPoles3D.reserve(aPolesArray->size());
+  for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
+    GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+    aPoles3D.push_back(aSketch->to3D(aPole->x(), aPole->y()));
+  }
+  // collect weights
+  std::vector<double> aWeights;
+  aWeights.reserve(aWeightsArray->size());
+  for (int anIndex = 0; anIndex < aWeightsArray->size(); ++anIndex)
+    aWeights.push_back(aWeightsArray->value(anIndex));
+
+  // create result non-periodic B-spline curve
+  GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bspline(aPoles3D, aWeights, false);
+
+  ResultConstructionPtr aResult = document()->createConstruction(data(), 0);
+  aResult->setShape(anEdge);
+  aResult->setIsInHistory(false);
+  setResult(aResult, 0);
+}
+
+bool SketchPlugin_BSpline::isFixed() {
+  return data()->selection(EXTERNAL_ID())->context().get() != NULL;
+}
+
+void SketchPlugin_BSpline::attributeChanged(const std::string& theID) {
+  // the second condition for unability to move external segments anywhere
+  if (theID == EXTERNAL_ID() || isFixed()) {
+    std::shared_ptr<GeomAPI_Shape> aSelection = data()->selection(EXTERNAL_ID())->value();
+    if (!aSelection) {
+      // empty shape in selection shows that the shape is equal to context
+      ResultPtr anExtRes = selection(EXTERNAL_ID())->context();
+      if (anExtRes)
+        aSelection = anExtRes->shape();
+    }
+////    // update arguments due to the selection value
+////    if (aSelection && !aSelection->isNull() && aSelection->isEdge()) {
+////      std::shared_ptr<GeomAPI_Edge> anEdge(new GeomAPI_Edge(aSelection));
+////      std::shared_ptr<GeomAPI_Ellipse> anEllipse = anEdge->ellipse();
+////
+////      bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+////      std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr =
+////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(CENTER_ID()));
+////      aCenterAttr->setValue(sketch()->to2D(anEllipse->center()));
+////
+////      std::shared_ptr<GeomDataAPI_Point2D> aFocusAttr =
+////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(FIRST_FOCUS_ID()));
+////      aFocusAttr->setValue(sketch()->to2D(anEllipse->firstFocus()));
+////
+////      std::shared_ptr<GeomDataAPI_Point2D> aStartAttr =
+////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(START_POINT_ID()));
+////      aStartAttr->setValue(sketch()->to2D(anEdge->firstPoint()));
+////
+////      std::shared_ptr<GeomDataAPI_Point2D> aEndAttr =
+////        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(attribute(END_POINT_ID()));
+////      aEndAttr->setValue(sketch()->to2D(anEdge->lastPoint()));
+////
+////      real(MAJOR_RADIUS_ID())->setValue(anEllipse->majorRadius());
+////      real(MINOR_RADIUS_ID())->setValue(anEllipse->minorRadius());
+////
+////      double aStartParam, aMidParam, aEndParam;
+////      anEllipse->parameter(anEdge->firstPoint(), tolerance, aStartParam);
+////      anEllipse->parameter(anEdge->middlePoint(), tolerance, aMidParam);
+////      anEllipse->parameter(anEdge->lastPoint(), tolerance, aEndParam);
+////      if (aEndParam < aStartParam)
+////        aEndParam += 2.0 * PI;
+////      if (aMidParam < aStartParam)
+////        aMidParam += 2.0 * PI;
+////      boolean(REVERSED_ID())->setValue(aMidParam > aEndParam);
+////
+////      data()->blockSendAttributeUpdated(aWasBlocked, false);
+////
+////      fillCharacteristicPoints();
+////    }
+  }
+////  else if (theID == CENTER_ID() || theID == FIRST_FOCUS_ID() ||
+////           theID == START_POINT_ID() || theID == END_POINT_ID())
+////    fillCharacteristicPoints();
+////  else if (theID == REVERSED_ID() && myParamDelta == 0.0)
+////    myParamDelta = 2.0 * PI;
+}
diff --git a/src/SketchPlugin/SketchPlugin_BSpline.h b/src/SketchPlugin/SketchPlugin_BSpline.h
new file mode 100644 (file)
index 0000000..c918a09
--- /dev/null
@@ -0,0 +1,78 @@
+// Copyright (C) 2019-2020  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_BSpline_H_
+#define SketchPlugin_BSpline_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+
+/**\class SketchPlugin_BSpline
+ * \ingroup Plugins
+ * \brief Feature for creation of the B-spline curve in the sketch.
+ */
+class SketchPlugin_BSpline : public SketchPlugin_SketchEntity
+{
+public:
+  /// Ellipse feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchBSpline");
+    return ID;
+  }
+
+  /// list of B-spline poles
+  inline static const std::string& POLES_ID()
+  {
+    static const std::string ID("poles");
+    return ID;
+  }
+
+  /// list of B-spline weights
+  inline static const std::string& WEIGHTS_ID()
+  {
+    static const std::string ID("weights");
+    return ID;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_BSpline::ID();
+    return MY_KIND;
+  }
+
+  /// Returns true is sketch element is under the rigid constraint
+  SKETCHPLUGIN_EXPORT virtual bool isFixed();
+
+  /// Called on change of any argument-attribute of this object
+  SKETCHPLUGIN_EXPORT virtual void attributeChanged(const std::string& theID);
+
+  /// Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// Use plugin manager for features creation
+  SketchPlugin_BSpline();
+
+protected:
+  /// \brief Initializes attributes of derived class.
+  virtual void initDerivedClassAttributes();
+};
+
+#endif
index ccab1cf931cf0b06a53dcdbdc2d9bdfd891b7cff..07d5638ad7e31790fa62d48a6ffe92499cc32029 100644 (file)
 
 #include "SketchPlugin_ConstraintCoincidenceInternal.h"
 
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
 SketchPlugin_ConstraintCoincidenceInternal::SketchPlugin_ConstraintCoincidenceInternal()
 {
 }
@@ -26,6 +30,12 @@ SketchPlugin_ConstraintCoincidenceInternal::SketchPlugin_ConstraintCoincidenceIn
 void SketchPlugin_ConstraintCoincidenceInternal::initAttributes()
 {
   SketchPlugin_ConstraintCoincidence::initAttributes();
+
+  data()->addAttribute(INDEX_ENTITY_A(), ModelAPI_AttributeInteger::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INDEX_ENTITY_A());
+
+  data()->addAttribute(INDEX_ENTITY_B(), ModelAPI_AttributeInteger::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), INDEX_ENTITY_B());
 }
 
 void SketchPlugin_ConstraintCoincidenceInternal::execute()
index fac0060ebb86b2963ba8aeb8100bb30a6efafdcd..d5a65f8101163da9a1f5a2699144ba2801747d34 100644 (file)
@@ -30,7 +30,7 @@
 class SketchPlugin_ConstraintCoincidenceInternal : public SketchPlugin_ConstraintCoincidence
 {
   public:
-  /// Coincidence constraint kind
+  /// \brief Coincidence constraint kind
   inline static const std::string& ID()
   {
     static const std::string MY_CONSTRAINT_COINCIDENCE_ID("SketchConstraintCoincidenceInternal");
@@ -43,7 +43,20 @@ class SketchPlugin_ConstraintCoincidenceInternal : public SketchPlugin_Constrain
     return MY_KIND;
   }
 
-  /// Returns the AIS preview
+  /// \brief Index of point in the array if the first attribute is an array
+  inline static const std::string& INDEX_ENTITY_A()
+  {
+    static const std::string MY_INDEX("ConstraintEntityA_Index");
+    return MY_INDEX;
+  }
+  /// \brief Index of point in the array if the second attribute is an array
+  inline static const std::string& INDEX_ENTITY_B()
+  {
+    static const std::string MY_INDEX("ConstraintEntityB_Index");
+    return MY_INDEX;
+  }
+
+  /// \brief Returns the AIS preview
   SKETCHPLUGIN_EXPORT virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
 
   /// \brief Creates a new part document if needed
diff --git a/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp b/src/SketchPlugin/SketchPlugin_MacroBSpline.cpp
new file mode 100644 (file)
index 0000000..ee47982
--- /dev/null
@@ -0,0 +1,333 @@
+// Copyright (C) 2019-2020  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_MacroBSpline.h>
+
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_Point.h>
+#include <SketchPlugin_Tools.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_AttributeRefAttrList.h>
+#include <ModelAPI_Events.h>
+#include <ModelAPI_EventReentrantMessage.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <GeomAlgoAPI_CompoundBuilder.h>
+#include <GeomAlgoAPI_EdgeBuilder.h>
+#include <GeomAlgoAPI_PointBuilder.h>
+
+#include <sstream>
+
+// Create Point feature coincident with the B-spline pole
+static FeaturePtr createAuxiliaryPole(FeaturePtr theBSpline,
+                                      AttributePoint2DArrayPtr theBSplinePoles,
+                                      const int thePoleIndex);
+// Create segment between consequtive B-spline poles
+static void createAuxiliarySegment(FeaturePtr theBSpline,
+                                   AttributePoint2DArrayPtr theBSplinePoles,
+                                   const int thePoleIndex1,
+                                   const int thePoleIndex2);
+// Create internal coincidence constraint with B-spline pole
+static void createInternalConstraint(SketchPlugin_Sketch* theSketch,
+                                     AttributePtr thePoint,
+                                     AttributePtr theBSplinePoles,
+                                     const int thePoleIndex);
+
+
+SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline()
+  : SketchPlugin_SketchEntity(),
+    myIsPeriodic(false)
+{
+}
+
+void SketchPlugin_MacroBSpline::initAttributes()
+{
+  data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
+  data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
+
+  data()->addAttribute(REF_POLES_ID(), ModelAPI_AttributeRefAttrList::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), REF_POLES_ID());
+
+  data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
+}
+
+void SketchPlugin_MacroBSpline::execute()
+{
+  FeaturePtr aBSpline = createBSplineFeature();
+
+  std::list<FeaturePtr> aControlPoles;
+  createControlPolygon(aBSpline, aControlPoles);
+  constraintsForPoles(aControlPoles);
+
+  // message to init reentrant operation
+  static Events_ID anId = ModelAPI_EventReentrantMessage::eventId();
+  ReentrantMessagePtr aMessage(new ModelAPI_EventReentrantMessage(anId, this));
+  // set here the last pole to make coincidence with the start point of the next B-spline curve
+  aMessage->setCreatedFeature(aControlPoles.back());
+  Events_Loop::loop()->send(aMessage);
+}
+
+// LCOV_EXCL_START
+std::string SketchPlugin_MacroBSpline::processEvent(
+                                              const std::shared_ptr<Events_Message>& theMessage)
+{
+  ReentrantMessagePtr aReentrantMessage =
+      std::dynamic_pointer_cast<ModelAPI_EventReentrantMessage>(theMessage);
+  if (aReentrantMessage) {
+    FeaturePtr aCreatedFeature = aReentrantMessage->createdFeature();
+    ObjectPtr anObject = aReentrantMessage->selectedObject();
+    AttributePtr anAttribute = aReentrantMessage->selectedAttribute();
+    std::shared_ptr<GeomAPI_Pnt2d> aClickedPoint = aReentrantMessage->clickedPoint();
+
+    if (aClickedPoint) {
+      // fill points list (it consists of 2 points to make editable the second one)
+      AttributePoint2DArrayPtr aPointArrayAttr =
+          std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+      aPointArrayAttr->setSize(2);
+      aPointArrayAttr->setPnt(0, aClickedPoint);
+      aPointArrayAttr->setPnt(1, aClickedPoint);
+
+      // fill weights
+      AttributeDoubleArrayPtr aWeightsArrayAttr = data()->realArray(WEIGHTS_ID());
+      aWeightsArrayAttr->setSize(2);
+      aWeightsArrayAttr->setValue(0, 1.0);
+      aWeightsArrayAttr->setValue(1, 1.0);
+
+      // fill reference attribute
+      AttributeRefAttrListPtr aRefAttrList =
+          std::dynamic_pointer_cast<ModelAPI_AttributeRefAttrList>(attribute(REF_POLES_ID()));
+      if (anAttribute) {
+        if (!anAttribute->owner() || !anAttribute->owner()->data()->isValid()) {
+          if (aCreatedFeature && anAttribute->id() == SketchPlugin_Point::COORD_ID())
+            anAttribute = aCreatedFeature->attribute(SketchPlugin_Point::COORD_ID());
+        }
+        aRefAttrList->append(anAttribute);
+      }
+    }
+    Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
+  }
+  return std::string();
+}
+// LCOV_EXCL_STOP
+
+FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature()
+{
+  FeaturePtr aBSpline = sketch()->addFeature(SketchPlugin_BSpline::ID());
+
+  AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+      aBSpline->attribute(SketchPlugin_BSpline::POLES_ID()));
+  AttributePoint2DArrayPtr aPolesMacro =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+  aPoles->assign(aPolesMacro);
+
+  AttributeDoubleArrayPtr aWeights =
+      aBSpline->data()->realArray(SketchPlugin_BSpline::WEIGHTS_ID());
+  AttributeDoubleArrayPtr aWeightsMacro = data()->realArray(WEIGHTS_ID());
+  int aSize = aWeightsMacro->size();
+  aWeights->setSize(aSize);
+  for (int index = 0; index < aSize; ++index)
+    aWeights->setValue(index, aWeightsMacro->value(index));
+
+  aBSpline->boolean(SketchPlugin_BSpline::AUXILIARY_ID())->setValue(
+      boolean(AUXILIARY_ID())->value());
+
+  aBSpline->execute();
+
+  return aBSpline;
+}
+
+void SketchPlugin_MacroBSpline::createControlPolygon(FeaturePtr theBSpline,
+                                                     std::list<FeaturePtr>& thePoles)
+{
+  AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
+      theBSpline->attribute(SketchPlugin_BSpline::POLES_ID()));
+  int aSize = aPoles->size();
+  // poles
+  for (int index = 0; index < aSize; ++index)
+    thePoles.push_back(createAuxiliaryPole(theBSpline, aPoles, index));
+  // segments
+  for (int index = 1; index < aSize; ++index)
+    createAuxiliarySegment(theBSpline, aPoles, index - 1, index);
+}
+
+void SketchPlugin_MacroBSpline::constraintsForPoles(const std::list<FeaturePtr>& thePoles)
+{
+  AttributeRefAttrListPtr aRefAttrList = data()->refattrlist(REF_POLES_ID());
+  std::list<std::pair<ObjectPtr, AttributePtr> > aList;
+  if (aRefAttrList)
+    aList = aRefAttrList->list();
+
+  SketchPlugin_Sketch* aSketch = sketch();
+
+  std::list<std::pair<ObjectPtr, AttributePtr> >::iterator aLIt = aList.begin();
+  std::list<FeaturePtr>::const_iterator aPIt = thePoles.begin();
+  for (; aLIt != aList.end() && aPIt != thePoles.end(); ++aPIt, ++aLIt) {
+    // firstly, check the attribute (in this case the object will be not empty too)
+    if (aLIt->second) {
+      SketchPlugin_Tools::createConstraintAttrAttr(aSketch,
+          SketchPlugin_ConstraintCoincidence::ID(),
+          (*aPIt)->attribute(SketchPlugin_Point::COORD_ID()), aLIt->second);
+    }
+    // now add coincidence with the result
+    else if (aLIt->first) {
+      SketchPlugin_Tools::createConstraintAttrObject(aSketch,
+          SketchPlugin_ConstraintCoincidence::ID(),
+          (*aPIt)->attribute(SketchPlugin_Point::COORD_ID()), aLIt->first);
+    }
+  }
+}
+
+AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
+{
+  SketchPlugin_Sketch* aSketch = sketch();
+  if (!aSketch)
+    return AISObjectPtr();
+
+  AttributePoint2DArrayPtr aPolesArray =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+  AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+
+  std::list<GeomShapePtr> aShapes;
+
+  // convert poles to 3D and collect weights
+  std::vector<GeomPointPtr> aPoles3D;
+  aPoles3D.reserve(aPolesArray->size());
+  std::vector<double> aWeights;
+  aWeights.reserve(aWeightsArray->size());
+  for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
+    double aWeight = aWeightsArray->value(anIndex);
+    if (aWeight < 1.e-10)
+      continue; // skip poles with zero weights
+
+    aWeights.push_back(aWeight);
+
+    GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+    GeomPointPtr aPole3D = aSketch->to3D(aPole->x(), aPole->y());
+    aPoles3D.push_back(aPole3D);
+    aShapes.push_back(GeomAlgoAPI_PointBuilder::vertex(aPole3D));
+  }
+
+  // create result non-periodic B-spline curve
+  GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bspline(aPoles3D, aWeights, false);
+  if (!anEdge)
+    return AISObjectPtr();
+
+  aShapes.push_back(anEdge);
+  GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
+
+  AISObjectPtr anAIS = thePrevious;
+  if (!anAIS)
+    anAIS.reset(new GeomAPI_AISObject());
+  anAIS->createShape(aCompound);
+
+  // Modify attributes
+  SketchPlugin_Tools::customizeFeaturePrs(anAIS, boolean(AUXILIARY_ID())->value());
+
+  return anAIS;
+}
+
+
+
+// ==========================     Auxiliary functions    ===========================================
+
+FeaturePtr createAuxiliaryPole(FeaturePtr theBSpline,
+                               AttributePoint2DArrayPtr theBSplinePoles,
+                               const int thePoleIndex)
+{
+  SketchPlugin_Sketch* aSketch =
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(theBSpline)->sketch();
+
+  // create child point equal to the B-spline's pole
+  FeaturePtr aPointFeature = aSketch->addFeature(SketchPlugin_Point::ID());
+  aPointFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+  aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theBSpline);
+
+  GeomPnt2dPtr aPole = theBSplinePoles->pnt(thePoleIndex);
+
+  AttributePoint2DPtr aCoord = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+      aPointFeature->attribute(SketchPlugin_Point::COORD_ID()));
+  aCoord->setValue(aPole);
+
+  aPointFeature->execute();
+
+  std::ostringstream aName;
+  aName << theBSpline->name() << "_" << theBSplinePoles->id() << "_" << thePoleIndex;
+  aPointFeature->data()->setName(aName.str());
+  aPointFeature->lastResult()->data()->setName(aName.str());
+
+  // internal constraint to keep position of the point
+  createInternalConstraint(aSketch, aCoord, theBSplinePoles, thePoleIndex);
+
+  return aPointFeature;
+}
+
+void createAuxiliarySegment(FeaturePtr theBSpline,
+                            AttributePoint2DArrayPtr theBSplinePoles,
+                            const int thePoleIndex1,
+                            const int thePoleIndex2)
+{
+  SketchPlugin_Sketch* aSketch =
+    std::dynamic_pointer_cast<SketchPlugin_Feature>(theBSpline)->sketch();
+
+  // create child segment between B-spline poles
+  FeaturePtr aLineFeature = aSketch->addFeature(SketchPlugin_Line::ID());
+  aLineFeature->boolean(SketchPlugin_Point::AUXILIARY_ID())->setValue(true);
+  aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(theBSpline);
+
+  AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    aLineFeature->attribute(SketchPlugin_Line::START_ID()));
+  aLineStart->setValue(theBSplinePoles->pnt(thePoleIndex1));
+
+  AttributePoint2DPtr aLineEnd = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+    aLineFeature->attribute(SketchPlugin_Line::END_ID()));
+  aLineEnd->setValue(theBSplinePoles->pnt(thePoleIndex2));
+
+  aLineFeature->execute();
+
+  std::ostringstream aName;
+  aName << theBSpline->name() << "_segment_" << thePoleIndex1 << "_" << thePoleIndex2;
+  aLineFeature->data()->setName(aName.str());
+  aLineFeature->lastResult()->data()->setName(aName.str());
+
+  // internal constraints to keep the segment position
+  createInternalConstraint(aSketch, aLineStart, theBSplinePoles, thePoleIndex1);
+  createInternalConstraint(aSketch, aLineEnd, theBSplinePoles, thePoleIndex2);
+}
+
+void createInternalConstraint(SketchPlugin_Sketch* theSketch,
+                              AttributePtr thePoint,
+                              AttributePtr theBSplinePoles,
+                              const int thePoleIndex)
+{
+  std::shared_ptr<SketchPlugin_ConstraintCoincidenceInternal> aConstraint =
+      std::dynamic_pointer_cast<SketchPlugin_ConstraintCoincidenceInternal>(
+      theSketch->addFeature(SketchPlugin_ConstraintCoincidenceInternal::ID()));
+  aConstraint->refattr(SketchPlugin_Constraint::ENTITY_A())->setAttr(thePoint);
+  aConstraint->refattr(SketchPlugin_Constraint::ENTITY_B())->setAttr(theBSplinePoles);
+  aConstraint->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B())
+      ->setValue(thePoleIndex);
+}
diff --git a/src/SketchPlugin/SketchPlugin_MacroBSpline.h b/src/SketchPlugin/SketchPlugin_MacroBSpline.h
new file mode 100644 (file)
index 0000000..f74b5bb
--- /dev/null
@@ -0,0 +1,110 @@
+// Copyright (C) 2019-2020  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_MacroBSpline_H_
+#define SketchPlugin_MacroBSpline_H_
+
+#include <ModelAPI_IReentrant.h>
+
+#include "SketchPlugin.h"
+
+#include "SketchPlugin_SketchEntity.h"
+
+#include <GeomAPI_IPresentable.h>
+
+class GeomAPI_Circ2d;
+class GeomAPI_Pnt2d;
+
+/**\class SketchPlugin_MacroBSpline
+ * \ingroup Plugins
+ * \brief Feature for creation of the new B-spline in Sketch.
+ */
+class SketchPlugin_MacroBSpline : public SketchPlugin_SketchEntity,
+                                  public GeomAPI_IPresentable,
+                                  public ModelAPI_IReentrant
+{
+public:
+  /// B-spline macro feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchMacroBSpline");
+    return ID;
+  }
+
+
+  /// list of B-spline poles
+  inline static const std::string& POLES_ID()
+  {
+    static const std::string ID("poles");
+    return ID;
+  }
+
+  /// list of references of B-spline poles
+  inline static const std::string& REF_POLES_ID()
+  {
+    static const std::string ID("poles_ref");
+    return ID;
+  }
+
+  /// list of B-spline weights
+  inline static const std::string& WEIGHTS_ID()
+  {
+    static const std::string ID("weights");
+    return ID;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_MacroBSpline::ID();
+    return MY_KIND;
+  }
+
+  /// \brief Request for initialization of data model of the feature: adding all attributes.
+  SKETCHPLUGIN_EXPORT virtual void initAttributes();
+
+  /// Returns the AIS preview
+  virtual AISObjectPtr getAISObject(AISObjectPtr thePrevious);
+
+  /// Creates a new part document if needed
+  SKETCHPLUGIN_EXPORT virtual void execute();
+
+  /// Reimplemented from ModelAPI_Feature::isMacro().
+  /// \returns true
+  SKETCHPLUGIN_EXPORT virtual bool isMacro() const {return true;};
+
+  SKETCHPLUGIN_EXPORT virtual bool isPreviewNeeded() const {return false;};
+
+  /// Apply information of the message to current object. It fills reference object,
+  /// tangent type and tangent point refence in case of tangent arc
+  virtual std::string processEvent(const std::shared_ptr<Events_Message>& theMessage);
+
+  /// Use plugin manager for features creation
+  SketchPlugin_MacroBSpline();
+
+private:
+  FeaturePtr createBSplineFeature();
+
+  void createControlPolygon(FeaturePtr theBSpline, std::list<FeaturePtr>& thePoles);
+  void constraintsForPoles(const std::list<FeaturePtr>& thePoles);
+
+  bool myIsPeriodic;
+};
+
+#endif
index ac1b442c82da8b06b32c948a929aaa7427cbc7c4..a6ef2a190e47f0960eb2964d3baeba18325a8b2c 100644 (file)
@@ -24,6 +24,7 @@
 #include <SketchPlugin_IntersectionPoint.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
 #include <SketchPlugin_Projection.h>
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
@@ -45,6 +46,7 @@
 #include <SketchPlugin_ConstraintTangent.h>
 #include <SketchPlugin_ConstraintVertical.h>
 #include <SketchPlugin_MacroArc.h>
+#include <SketchPlugin_MacroBSpline.h>
 #include <SketchPlugin_MacroCircle.h>
 #include <SketchPlugin_MultiRotation.h>
 #include <SketchPlugin_MultiTranslation.h>
@@ -147,6 +149,8 @@ SketchPlugin_Plugin::SketchPlugin_Plugin()
                               new SketchPlugin_SketchFeatureValidator);
   aFactory->registerValidator("SketchPlugin_MultiRotationAngleValidator",
                               new SketchPlugin_MultiRotationAngleValidator);
+  aFactory->registerValidator("SketchPlugin_BSplineValidator",
+                              new SketchPlugin_BSplineValidator);
 
   // register this plugin
   ModelAPI_Session::get()->registerPlugin(this);
@@ -201,6 +205,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_Circle);
   } else if (theFeatureID == SketchPlugin_Arc::ID()) {
     return FeaturePtr(new SketchPlugin_Arc);
+  } else if (theFeatureID == SketchPlugin_BSpline::ID()) {
+    return FeaturePtr(new SketchPlugin_BSpline);
   } else if (theFeatureID == SketchPlugin_Projection::ID()) {
     return FeaturePtr(new SketchPlugin_Projection);
   } else if (theFeatureID == SketchPlugin_ConstraintCoincidence::ID()) {
@@ -251,6 +257,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_Trim);
   } else if (theFeatureID == SketchPlugin_MacroArc::ID()) {
     return FeaturePtr(new SketchPlugin_MacroArc);
+  } else if (theFeatureID == SketchPlugin_MacroBSpline::ID()) {
+    return FeaturePtr(new SketchPlugin_MacroBSpline);
   } else if (theFeatureID == SketchPlugin_MacroCircle::ID()) {
     return FeaturePtr(new SketchPlugin_MacroCircle);
   } else if (theFeatureID == SketchPlugin_Ellipse::ID()) {
@@ -306,6 +314,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_Line::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Circle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Arc::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_BSpline::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Ellipse::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_EllipticArc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Projection::ID(), aHasSketchPlane);
@@ -331,6 +340,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_Split::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Trim::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroArc::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_MacroBSpline::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroCircle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroEllipse::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroEllipticArc::ID(), aHasSketchPlane);
index 8e1bccbf6c655d459453992cfb33d4a09a6b2f5e..a974f743763d601c821430017f850041df53336d 100644 (file)
@@ -65,7 +65,9 @@
 #include <GeomAPI_Lin.h>
 #include <GeomAPI_Edge.h>
 #include <GeomAPI_Vertex.h>
+
 #include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
 
 #include <algorithm>
 #include <cmath>
@@ -1779,3 +1781,20 @@ bool SketchPlugin_MultiRotationAngleValidator::isValid(const AttributePtr& theAt
 
   return true;
 }
+
+bool SketchPlugin_BSplineValidator::isValid(const AttributePtr& theAttribute,
+                                            const std::list<std::string>& theArguments,
+                                            Events_InfoMessage& theError) const
+{
+  AttributePoint2DArrayPtr aPolesArray =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+  if (!aPolesArray)
+    return false;
+
+  if (aPolesArray->size() < 2) {
+    theError = "Number of B-spline poles should be 2 and more";
+    return false;
+  }
+
+  return true;
+}
index b3fe8f57464ee41781dcfe9d114f9caaac735a89..1b20c45fdcdb45af3e4028af684cb9cd0c6e1c7f 100644 (file)
@@ -531,4 +531,19 @@ class SketchPlugin_MultiRotationAngleValidator : public ModelAPI_AttributeValida
                        Events_InfoMessage& theError) const;
 };
 
+/**\class SketchPlugin_BSplineValidator
+ * \ingroup Validators
+ * \brief Validator for checking poles/weights of B-spline curve.
+ */
+class SketchPlugin_BSplineValidator : public ModelAPI_AttributeValidator
+{
+  //! returns true if attribute is valid
+  //! \param theAttribute the checked attribute
+  //! \param theArguments arguments of the attribute
+  //! \param theError error message
+  virtual bool isValid(const AttributePtr& theAttribute,
+                       const std::list<std::string>& theArguments,
+                       Events_InfoMessage& theError) const;
+};
+
 #endif
diff --git a/src/SketchPlugin/icons/bspline.png b/src/SketchPlugin/icons/bspline.png
new file mode 100644 (file)
index 0000000..149d19e
Binary files /dev/null and b/src/SketchPlugin/icons/bspline.png differ
diff --git a/src/SketchPlugin/icons/bspline_p.png b/src/SketchPlugin/icons/bspline_p.png
new file mode 100644 (file)
index 0000000..a23ade1
Binary files /dev/null and b/src/SketchPlugin/icons/bspline_p.png differ
index 0c77223de177eb7e0fabc366fd3c5e1002df68e6..2f3ee27615c0e378f89f6132dea3956c481f2a16 100644 (file)
@@ -6,6 +6,7 @@
         nested="SketchPoint SketchIntersectionPoint SketchLine
                 SketchCircle SketchMacroCircle SketchArc SketchMacroArc
                 SketchEllipse SketchMacroEllipse SketchEllipticArc SketchMacroEllipticArc
+                SketchBSpline SketchMacroBSpline
                 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">
+        <sketch-bspline_selector id="poles"
+                                 weights="weights"
+                                 title="Poles and weights"
+                                 tooltip="B-spline poles and weights"
+                                 enable_value="enable_by_preferences">
+          <validator id="SketchPlugin_BSplineValidator"/>
+        </sketch-bspline_selector>
+        <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="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"
index fab1f0356d3f363e00fff20140a125395f3172e9..59f33e0f6de798010a77dec8df3b94cefb8d7600 100644 (file)
@@ -27,7 +27,9 @@ SET(PLANEGCSSOLVER_HEADERS
     PlaneGCSSolver_EdgeWrapper.h
     PlaneGCSSolver_EntityWrapper.h
     PlaneGCSSolver_PointWrapper.h
+    PlaneGCSSolver_PointArrayWrapper.h
     PlaneGCSSolver_ScalarWrapper.h
+    PlaneGCSSolver_ScalarArrayWrapper.h
     PlaneGCSSolver_AngleWrapper.h
     PlaneGCSSolver_BooleanWrapper.h
     PlaneGCSSolver_Tools.h
@@ -39,7 +41,9 @@ SET(PLANEGCSSOLVER_SOURCES
     PlaneGCSSolver_ConstraintWrapper.cpp
     PlaneGCSSolver_EdgeWrapper.cpp
     PlaneGCSSolver_PointWrapper.cpp
+    PlaneGCSSolver_PointArrayWrapper.cpp
     PlaneGCSSolver_ScalarWrapper.cpp
+    PlaneGCSSolver_ScalarArrayWrapper.cpp
     PlaneGCSSolver_AngleWrapper.cpp
     PlaneGCSSolver_BooleanWrapper.cpp
     PlaneGCSSolver_Tools.cpp
index ca463c53d70f063745d9f062bf7c250cc6810d24..7ccedd950459c17875e251758b919f9c7ca659f3 100644 (file)
 
 #include <PlaneGCSSolver_AngleWrapper.h>
 #include <PlaneGCSSolver_AttributeBuilder.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
 #include <PlaneGCSSolver_PointWrapper.h>
 #include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
 #include <PlaneGCSSolver_BooleanWrapper.h>
 
+#include <GeomAPI_Pnt2d.h>
 #include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
 #include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_MultiRotation.h>
 
@@ -80,6 +85,40 @@ static EntityWrapperPtr createScalar(const AttributePtr&     theAttribute,
   return aWrapper;
 }
 
+static EntityWrapperPtr createScalarArray(const AttributePtr&     theAttribute,
+                                          PlaneGCSSolver_Storage* theStorage)
+{
+  AttributeDoubleArrayPtr anArray =
+      std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(theAttribute);
+  if (!anArray || !anArray->isInitialized())
+    return EntityWrapperPtr();
+
+  int aSize = anArray->size();
+  GCS::VEC_pD aParameters;
+  aParameters.reserve(aSize);
+  for (int index = 0; index < aSize; ++index) {
+    double* aParam = createParameter(theStorage);
+    *aParam = anArray->value(index);
+    aParameters.push_back(aParam);
+  }
+
+  return EntityWrapperPtr(new PlaneGCSSolver_ScalarArrayWrapper(aParameters));
+}
+
+static PointWrapperPtr createPoint(const GeomPnt2dPtr& thePoint, PlaneGCSSolver_Storage* theStorage)
+{
+  GCSPointPtr aNewPoint(new GCS::Point);
+
+  aNewPoint->x = createParameter(theStorage);
+  aNewPoint->y = createParameter(theStorage);
+  if (thePoint) {
+    *(aNewPoint->x) = thePoint->x();
+    *(aNewPoint->y) = thePoint->y();
+  }
+
+  return PointWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint));
+}
+
 static EntityWrapperPtr createPoint(const AttributePtr&     theAttribute,
                                     PlaneGCSSolver_Storage* theStorage)
 {
@@ -88,16 +127,29 @@ static EntityWrapperPtr createPoint(const AttributePtr&     theAttribute,
   if (!aPoint2D)
     return EntityWrapperPtr();
 
-  GCSPointPtr aNewPoint(new GCS::Point);
+  GeomPnt2dPtr aPnt;
+  if (aPoint2D->isInitialized())
+    aPnt = aPoint2D->pnt();
 
-  aNewPoint->x = createParameter(theStorage);
-  aNewPoint->y = createParameter(theStorage);
-  if (aPoint2D->isInitialized()) {
-    *(aNewPoint->x) = aPoint2D->x();
-    *(aNewPoint->y) = aPoint2D->y();
-  }
+  return createPoint(aPnt, theStorage);
+}
 
-  return EntityWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint));
+static EntityWrapperPtr createPointArray(const AttributePtr& theAttribute,
+                                         PlaneGCSSolver_Storage* theStorage)
+{
+  std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+  if (!aPointArray)
+    return EntityWrapperPtr();
+
+  int aSize = aPointArray->size();
+
+  std::vector<PointWrapperPtr> aPointWrappers;
+  aPointWrappers.reserve(aSize);
+  for (int index = 0; index < aSize; ++index)
+    aPointWrappers.push_back(createPoint(aPointArray->pnt(index), theStorage));
+
+  return EntityWrapperPtr(new PlaneGCSSolver_PointArrayWrapper(aPointWrappers));
 }
 
 EntityWrapperPtr PlaneGCSSolver_AttributeBuilder::createAttribute(
@@ -112,6 +164,10 @@ EntityWrapperPtr PlaneGCSSolver_AttributeBuilder::createAttribute(
     aResult = createScalar(theAttribute, myStorage);
   if (!aResult)
     aResult = createBoolean(theAttribute);
+  if (!aResult)
+    aResult = createPointArray(theAttribute, myStorage);
+  if (!aResult)
+    aResult = createScalarArray(theAttribute, myStorage);
   if (aResult && !myStorage)
     aResult->setExternal(true);
   return aResult;
index 0f46e7544d73920b8f3349618b3f1a6dc7c4d982..eea27bf06faccc7087337d4481a3a7b081ee49e3 100644 (file)
@@ -46,13 +46,16 @@ enum SketchSolver_EntityType {
   ENTITY_UNKNOWN = 0,
   ENTITY_BOOLEAN,
   ENTITY_SCALAR,
+  ENTITY_SCALAR_ARRAY,
   ENTITY_ANGLE,
   ENTITY_POINT,
+  ENTITY_POINT_ARRAY,
   ENTITY_LINE,
   ENTITY_CIRCLE,
   ENTITY_ARC,
   ENTITY_ELLIPSE,
-  ENTITY_ELLIPTIC_ARC
+  ENTITY_ELLIPTIC_ARC,
+  ENTITY_BSPLINE
 };
 
 /// Types of constraints
index f9683203880051e28acbc8a99d0e71ef8d4cf014..669aece33073ca8e85916c47b7fe8c0f875fcd61 100644 (file)
 #include <PlaneGCSSolver_EdgeWrapper.h>
 #include <cmath>
 
-static bool isLine(const GCSCurvePtr& theEntity)
+template <typename TYPE>
+static bool isCurve(const GCSCurvePtr& theEntity)
 {
-  return std::dynamic_pointer_cast<GCS::Line>(theEntity).get();
-}
-
-static bool isCircle(const GCSCurvePtr& theEntity)
-{
-  return std::dynamic_pointer_cast<GCS::Circle>(theEntity).get();
-}
-
-static bool isArc(const GCSCurvePtr& theEntity)
-{
-  return std::dynamic_pointer_cast<GCS::Arc>(theEntity).get();
-}
-
-static bool isEllipse(const GCSCurvePtr& theEntity)
-{
-  return std::dynamic_pointer_cast<GCS::Ellipse>(theEntity).get();
-}
-
-static bool isEllipticArc(const GCSCurvePtr& theEntity)
-{
-  return std::dynamic_pointer_cast<GCS::ArcOfEllipse>(theEntity).get();
+  return std::dynamic_pointer_cast<TYPE>(theEntity).get();
 }
 
 
 PlaneGCSSolver_EdgeWrapper::PlaneGCSSolver_EdgeWrapper(const GCSCurvePtr theEntity)
   : myEntity(theEntity)
 {
-  if (isLine(myEntity))
+  if (isCurve<GCS::Line>(myEntity))
     myType = ENTITY_LINE;
-  else if (isArc(myEntity))
+  else if (isCurve<GCS::Arc>(myEntity))
     myType = ENTITY_ARC;
-  else if (isCircle(myEntity))
+  else if (isCurve<GCS::Circle>(myEntity))
     myType = ENTITY_CIRCLE;
-  else if (isEllipticArc(myEntity))
+  else if (isCurve<GCS::ArcOfEllipse>(myEntity))
     myType = ENTITY_ELLIPTIC_ARC;
-  else if (isEllipse(myEntity))
+  else if (isCurve<GCS::Ellipse>(myEntity))
     myType = ENTITY_ELLIPSE;
+  else if (isCurve<GCS::BSpline>(myEntity))
+    myType = ENTITY_BSPLINE;
 }
 
 static double squareDistance(const GCS::Point& theP1, const GCS::Point& theP2)
index 400319aed4bd9804a46ec5c2c118da1d8473c9d7..78dc0d7c985913e9dbcda2c95476bf0db25de391 100644 (file)
 #include <PlaneGCSSolver_FeatureBuilder.h>
 #include <PlaneGCSSolver_EdgeWrapper.h>
 #include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
 #include <PlaneGCSSolver_ScalarWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
 #include <PlaneGCSSolver_BooleanWrapper.h>
 #include <PlaneGCSSolver_Tools.h>
 
 #include <SketchPlugin_Arc.h>
+#include <SketchPlugin_BSpline.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_EllipticArc.h>
@@ -46,6 +49,7 @@ static EntityWrapperPtr createArc(const AttributeEntityMap&    theAttributes,
 static EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes);
 static EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
                                           PlaneGCSSolver_Storage*   theStorage);
+static EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes);
 
 
 PlaneGCSSolver_FeatureBuilder::PlaneGCSSolver_FeatureBuilder(
@@ -102,6 +106,9 @@ EntityWrapperPtr PlaneGCSSolver_FeatureBuilder::createFeature(FeaturePtr theFeat
   // Arc of ellipse
   else if (aFeatureKind == SketchPlugin_EllipticArc::ID())
     aResult = createEllipticArc(myAttributes, myStorage);
+  // B-spline curve
+  else if (aFeatureKind == SketchPlugin_BSpline::ID())
+    aResult = createBSpline(myAttributes);
   // Point (it has low probability to be an attribute of constraint, so it is checked at the end)
   else if (aFeatureKind == SketchPlugin_Point::ID() ||
            aFeatureKind == SketchPlugin_IntersectionPoint::ID()) {
@@ -288,6 +295,38 @@ EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
   return anEllipseWrapper;
 }
 
+EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
+{
+  std::shared_ptr<GCS::BSpline> aNewSpline(new GCS::BSpline);
+
+  aNewSpline->degree = 3;
+  aNewSpline->periodic = false;
+
+  AttributeEntityMap::const_iterator anIt = theAttributes.begin();
+  for (; anIt != theAttributes.end(); ++anIt) {
+    const std::string& anAttrID = anIt->first->id();
+    if (anAttrID == SketchPlugin_BSpline::POLES_ID()) {
+      PointArrayWrapperPtr anArray =
+          std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
+
+      int aSize = anArray->size();
+      aNewSpline->poles.reserve(aSize);
+      for (int anIndex = 0; anIndex < aSize; ++anIndex)
+        aNewSpline->poles.push_back(*anArray->value(anIndex)->point());
+
+      aNewSpline->start = aNewSpline->poles.front();
+      aNewSpline->end = aNewSpline->poles.back();
+    }
+    else if (anAttrID == SketchPlugin_BSpline::WEIGHTS_ID()) {
+      ScalarArrayWrapperPtr anArray =
+          std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
+      aNewSpline->weights = anArray->array();
+    }
+  }
+
+  return EdgeWrapperPtr(new PlaneGCSSolver_EdgeWrapper(aNewSpline));
+}
+
 bool isAttributeApplicable(const std::string& theAttrName, const std::string& theOwnerName)
 {
   if (theOwnerName == SketchPlugin_Arc::ID()) {
@@ -329,6 +368,10 @@ bool isAttributeApplicable(const std::string& theAttrName, const std::string& th
            theAttrName == SketchPlugin_EllipticArc::END_POINT_ID() ||
            theAttrName == SketchPlugin_EllipticArc::REVERSED_ID();
   }
+  else if (theOwnerName == SketchPlugin_BSpline::ID()) {
+    return theAttrName == SketchPlugin_BSpline::POLES_ID() ||
+           theAttrName == SketchPlugin_BSpline::WEIGHTS_ID();
+  }
 
   // suppose that all remaining features are points
   return theAttrName == SketchPlugin_Point::COORD_ID();
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointArrayWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointArrayWrapper.cpp
new file mode 100644 (file)
index 0000000..33a7954
--- /dev/null
@@ -0,0 +1,26 @@
+// Copyright (C) 2019-2020  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 <PlaneGCSSolver_PointArrayWrapper.h>
+
+PlaneGCSSolver_PointArrayWrapper::PlaneGCSSolver_PointArrayWrapper(
+    const std::vector<PointWrapperPtr>& thePoints)
+  : myPoints(thePoints)
+{
+}
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointArrayWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_PointArrayWrapper.h
new file mode 100644 (file)
index 0000000..8752b79
--- /dev/null
@@ -0,0 +1,51 @@
+// Copyright (C) 2019-2020  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 PlaneGCSSolver_PointArrayWrapper_H_
+#define PlaneGCSSolver_PointArrayWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_PointWrapper.h>
+
+/**
+ *  Wrapper providing operations with arrays of PlaneGCS points.
+ */
+class PlaneGCSSolver_PointArrayWrapper : public PlaneGCSSolver_EntityWrapper
+{
+public:
+  PlaneGCSSolver_PointArrayWrapper(const std::vector<PointWrapperPtr>& thePoints);
+
+  /// \brief Return wrapper of PlaneGCS point
+  const PointWrapperPtr& value(const int theIndex) const
+  { return myPoints[theIndex]; }
+
+  /// \breif Size of array
+  int size() const { return (int)myPoints.size(); }
+
+  /// \brief Return type of current entity
+  virtual SketchSolver_EntityType type() const
+  { return ENTITY_POINT_ARRAY; }
+
+private:
+  std::vector<PointWrapperPtr> myPoints;
+};
+
+typedef std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> PointArrayWrapperPtr;
+
+#endif
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarArrayWrapper.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarArrayWrapper.cpp
new file mode 100644 (file)
index 0000000..b599f8f
--- /dev/null
@@ -0,0 +1,25 @@
+// Copyright (C) 2019-2020  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 <PlaneGCSSolver_ScalarArrayWrapper.h>
+
+PlaneGCSSolver_ScalarArrayWrapper::PlaneGCSSolver_ScalarArrayWrapper(const GCS::VEC_pD& theParam)
+  : myValue(theParam)
+{
+}
diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarArrayWrapper.h b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_ScalarArrayWrapper.h
new file mode 100644 (file)
index 0000000..40746cf
--- /dev/null
@@ -0,0 +1,47 @@
+// Copyright (C) 2019-2020  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 PlaneGCSSolver_ScalarArrayWrapper_H_
+#define PlaneGCSSolver_ScalarArrayWrapper_H_
+
+#include <PlaneGCSSolver_Defs.h>
+#include <PlaneGCSSolver_EntityWrapper.h>
+
+/**
+ *  Wrapper providing operations with array of PlaneGCS scalars.
+ */
+class PlaneGCSSolver_ScalarArrayWrapper : public PlaneGCSSolver_EntityWrapper
+{
+public:
+  PlaneGCSSolver_ScalarArrayWrapper(const GCS::VEC_pD& theParam);
+
+  /// \brief Return array of PlaneGCS parameters
+  const GCS::VEC_pD& array() const { return myValue; }
+
+  /// \brief Return type of current entity
+  virtual SketchSolver_EntityType type() const
+  { return ENTITY_SCALAR_ARRAY; }
+
+protected:
+  GCS::VEC_pD myValue; ///< list of pointers to values provided by the storage
+};
+
+typedef std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> ScalarArrayWrapperPtr;
+
+#endif
index 439bc8184c4f85bbf557ac6b55d0b138cc185fb1..dc6d72ff391897d05cf5a1b7046995baf0cc2101 100644 (file)
@@ -19,8 +19,6 @@
 
 #include <PlaneGCSSolver_ScalarWrapper.h>
 
-#include <cmath>
-
 PlaneGCSSolver_ScalarWrapper::PlaneGCSSolver_ScalarWrapper(double *const theParam)
   : myValue(theParam)
 {
index a5788f23a82f8e37224d769a52f4c91cf07bc89e..9349f5c3099b0a33577095a3f7639a6474545566 100644 (file)
@@ -23,6 +23,8 @@
 #include <PlaneGCSSolver_ConstraintWrapper.h>
 #include <PlaneGCSSolver_EdgeWrapper.h>
 #include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
 #include <PlaneGCSSolver_Tools.h>
 
 #include <PlaneGCSSolver_AttributeBuilder.h>
@@ -33,6 +35,8 @@
 #include <GeomAPI_Pnt2d.h>
 #include <GeomAPI_XY.h>
 #include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+#include <ModelAPI_AttributeDoubleArray.h>
 #include <ModelAPI_AttributeRefAttr.h>
 #include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_Projection.h>
@@ -626,6 +630,23 @@ void PlaneGCSSolver_Storage::refresh() const
       }
       continue;
     }
+    std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anIt->first);
+    if (aPointArray) {
+      std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> anArrayWrapper =
+          std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
+      int aSize = aPointArray->size();
+      for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+        GeomPnt2dPtr anOriginal = aPointArray->pnt(anIndex);
+        GCSPointPtr aGCSPoint = anArrayWrapper->value(anIndex)->point();
+        if (fabs(anOriginal->x() - (*aGCSPoint->x)) > aTol ||
+            fabs(anOriginal->y() - (*aGCSPoint->y)) > aTol) {
+          aPointArray->setPnt(anIndex, *aGCSPoint->x, *aGCSPoint->y);
+          addOwnerToSet(anIt->first, anUpdatedFeatures);
+        }
+      }
+      continue;
+    }
     AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
     if (aScalar) {
       ScalarWrapperPtr aScalarWrapper =
@@ -636,6 +657,20 @@ void PlaneGCSSolver_Storage::refresh() const
       }
       continue;
     }
+    AttributeDoubleArrayPtr aRealArray =
+        std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(anIt->first);
+    if (aRealArray) {
+      std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> anArrayWrapper =
+          std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
+      int aSize = aRealArray->size();
+      for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+        if (fabs(aRealArray->value(anIndex) - *anArrayWrapper->array()[anIndex]) > aTol) {
+          aRealArray->setValue(anIndex, *anArrayWrapper->array()[anIndex]);
+          addOwnerToSet(anIt->first, anUpdatedFeatures);
+        }
+      }
+      continue;
+    }
   }
 
   // notify listeners about features update
index a438391ab3c49a39ccdcc035f1330d23d753f2ac..c1b83d3f85865e04de66ee6297fe9b888df37627 100644 (file)
@@ -191,6 +191,13 @@ std::shared_ptr<SketchSolver_ConstraintMovement> PlaneGCSSolver_Tools::createMov
       new SketchSolver_ConstraintMovement(theMovedAttribute));
 }
 
+std::shared_ptr<SketchSolver_ConstraintMovement> PlaneGCSSolver_Tools::createMovementConstraint(
+    const std::pair<AttributePtr, int>& theMovedPointInArray)
+{
+  return std::shared_ptr<SketchSolver_ConstraintMovement>(
+      new SketchSolver_ConstraintMovement(theMovedPointInArray.first, theMovedPointInArray.second));
+}
+
 
 
 ConstraintWrapperPtr PlaneGCSSolver_Tools::createConstraint(
index a02a9948c77a2302f86a4b7d48176b33f3d3f4ea..d90fecbe0c67f320e9dbfd41c5e2481b15157519 100644 (file)
@@ -45,6 +45,9 @@ namespace PlaneGCSSolver_Tools
   /// \brief Creates temporary constraint to fix the attribute after movement
   std::shared_ptr<SketchSolver_ConstraintMovement>
       createMovementConstraint(AttributePtr theMovedAttribute);
+  /// \brief Creates temporary constraint to fix the point in array after movement
+  std::shared_ptr<SketchSolver_ConstraintMovement>
+      createMovementConstraint(const std::pair<AttributePtr, int>& theMovedPointInArray);
 
   /// \brief Creates new constraint using given parameters
   /// \param theConstraint [in]  original constraint
index 48c0fa5b80d63454f15ee4b12fa0a563c4b941d7..17720fdc4c3855a4a995e25075523c5510aa17d9 100644 (file)
@@ -233,7 +233,7 @@ void SketchSolver_Constraint::getAttributes(
     SketchSolver_EntityType aType = anEntity->type();
     if (aType == ENTITY_UNKNOWN)
       continue;
-    else if (aType == ENTITY_POINT)
+    else if (aType == ENTITY_POINT || aType == ENTITY_POINT_ARRAY)
       theAttributes[aPtInd++] = anEntity; // the point is created
     else { // another entity (not a point) is created
       if (aEntInd < anInitNbOfAttr)
index 4bac7dd1fda160092024b66cad9bc7fc5ed99d92..f4b616b9ee30c6bcb2fd19e9bd61ca834169693a 100644 (file)
 
 #include <SketchSolver_ConstraintCoincidence.h>
 #include <SketchSolver_Error.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
 #include <PlaneGCSSolver_Tools.h>
 #include <PlaneGCSSolver_UpdateCoincidence.h>
 
 #include <GeomDataAPI_Point2D.h>
 
+#include <ModelAPI_AttributeInteger.h>
+
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
 #include <SketchPlugin_Ellipse.h>
@@ -186,6 +189,20 @@ static void processEllipticArcExtremities(SketchSolver_ConstraintType& theType,
   }
 }
 
+static void getPointFromArray(EntityWrapperPtr& theArray,
+                              const ConstraintPtr& theConstraint,
+                              const std::string& theIndexAttrId)
+{
+  if (theArray && theArray->type() == ENTITY_POINT_ARRAY) {
+    AttributeIntegerPtr anIndexAttr = theConstraint->integer(theIndexAttrId);
+    if (anIndexAttr) {
+      PointArrayWrapperPtr aPointsArray =
+          std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(theArray);
+      theArray = aPointsArray->value(anIndexAttr->value());
+    }
+  }
+}
+
 
 void SketchSolver_ConstraintCoincidence::process()
 {
@@ -244,6 +261,12 @@ void SketchSolver_ConstraintCoincidence::getAttributes(
     getCoincidentFeatureExtremities(myBaseConstraint, myStorage, myFeatureExtremities);
   } else
     myErrorMsg = SketchSolver_Error::INCORRECT_ATTRIBUTE();
+
+  // process internal coincidence with a point in the array of points
+  getPointFromArray(theAttributes[0], myBaseConstraint,
+                    SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+  getPointFromArray(theAttributes[1], myBaseConstraint,
+                    SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
 }
 
 void SketchSolver_ConstraintCoincidence::notify(const FeaturePtr&      theFeature,
index 8e38fa6b8303487f7acead82f677d97b0c9b0660..3384416c7102c4ef375157b9c3d8907f5212d953 100644 (file)
@@ -22,6 +22,7 @@
 #include <SketchSolver_Manager.h>
 
 #include <PlaneGCSSolver_EdgeWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
 #include <PlaneGCSSolver_PointWrapper.h>
 
 #include <SketchPlugin_Arc.h>
@@ -53,12 +54,14 @@ SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(FeaturePtr theF
 {
 }
 
-SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(AttributePtr thePoint)
+SketchSolver_ConstraintMovement::SketchSolver_ConstraintMovement(AttributePtr theAttribute,
+                                                                 const int thePointIndex)
   : SketchSolver_ConstraintFixed(ConstraintPtr()),
-    myDraggedPoint(thePoint),
+    myDraggedAttribute(theAttribute),
+    myDraggedPointIndex(thePointIndex),
     mySimpleMove(true)
 {
-  myMovedFeature = ModelAPI_Feature::feature(thePoint->owner());
+  myMovedFeature = ModelAPI_Feature::feature(theAttribute->owner());
 }
 
 void SketchSolver_ConstraintMovement::blockEvents(bool isBlocked)
@@ -115,22 +118,27 @@ ConstraintWrapperPtr SketchSolver_ConstraintMovement::initMovement()
     return aConstraint;
   }
 
-  EntityWrapperPtr anEntity =
-      myDraggedPoint ? myStorage->entity(myDraggedPoint) : myStorage->entity(myMovedFeature);
+  EntityWrapperPtr anEntity = myDraggedAttribute ? myStorage->entity(myDraggedAttribute)
+                                                 : myStorage->entity(myMovedFeature);
   if (!anEntity) {
     myStorage->update(myMovedFeature, true);
-    anEntity =
-        myDraggedPoint ? myStorage->entity(myDraggedPoint) : myStorage->entity(myMovedFeature);
+    anEntity = myDraggedAttribute ? myStorage->entity(myDraggedAttribute)
+                                  : myStorage->entity(myMovedFeature);
     if (!anEntity)
       return aConstraint;
   }
 
-  mySimpleMove = isSimpleMove(myMovedFeature, myDraggedPoint);
+  mySimpleMove = isSimpleMove(myMovedFeature, myDraggedAttribute);
 
-  if (mySimpleMove)
+  if (mySimpleMove) {
+    if (anEntity->type() == ENTITY_POINT_ARRAY) {
+      anEntity = std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anEntity)
+                 ->value(myDraggedPointIndex);
+    }
     aConstraint = fixFeature(anEntity);
+  }
   else {
-    if (myDraggedPoint) // start or end point of arc has been moved
+    if (myDraggedAttribute) // start or end point of arc has been moved
       aConstraint = fixArcExtremity(anEntity);
     else if (anEntity->type() == ENTITY_CIRCLE || anEntity->type() == ENTITY_ARC) {
       // arc or circle has been moved
@@ -311,7 +319,8 @@ void SketchSolver_ConstraintMovement::moveTo(
 #ifdef CHANGE_RADIUS_WHILE_MOVE
   int aMaxSize = mySimpleMove ? (int)myFixedValues.size() : 2;
 #else
-  int aMaxSize = myMovedFeature->getKind() == SketchPlugin_Line::ID() && !myDraggedPoint ? 4 : 2;
+  int aMaxSize =
+      myMovedFeature->getKind() == SketchPlugin_Line::ID() && !myDraggedAttribute ? 4 : 2;
 #endif
   for (int i = 0; i < aMaxSize; ++i)
     myFixedValues[i] += aDelta[i % 2];
index bfbe1f1ed644f2fc442e11ef918c4cd33275ebcc..451ddb462ee41672e0b9d4cbecafb0df4dd406c9 100644 (file)
@@ -39,7 +39,7 @@ public:
   SketchSolver_ConstraintMovement(FeaturePtr theFeature);
 
   /// Creates movement constraint based on point
-  SketchSolver_ConstraintMovement(AttributePtr thePoint);
+  SketchSolver_ConstraintMovement(AttributePtr theMovedAttribute, const int thePointIndex = -1);
 
   /// \brief Set coordinates of the start point of the movement
   void startPoint(const std::shared_ptr<GeomAPI_Pnt2d>& theStartPoint);
@@ -74,7 +74,8 @@ protected:
 
 private:
   FeaturePtr       myMovedFeature; ///< fixed feature (if set, myBaseConstraint should be NULL)
-  AttributePtr     myDraggedPoint; ///< one of the feature points which has been moved
+  AttributePtr     myDraggedAttribute; ///< one of the feature points which has been moved
+  int              myDraggedPointIndex; ///< index of the point if the moved attribute is an array
   std::shared_ptr<GeomAPI_Pnt2d> myStartPoint; ///< start point of the movement
 
   bool mySimpleMove; ///< simple move, thus all parameters should be increased by movement delta
index 96c0a29687a66e1008520dd4d398e5244df9ce18..4f1f5ee863388733c7b2e335ac606d1e2316c4a5 100644 (file)
@@ -164,10 +164,11 @@ static SolverConstraintPtr move(StoragePtr theStorage,
                                 int theSketchDOF,
                                 bool theEventsBlocked,
                                 Type theFeatureOrPoint,
+                                const EntityWrapperPtr& theSolverEntity,
                                 const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
                                 const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
 {
-  bool isEntityExists = (theStorage->entity(theFeatureOrPoint).get() != 0);
+  bool isEntityExists = (theSolverEntity.get() != 0);
   if (theSketchDOF == 0 && isEntityExists) {
     // avoid moving elements of fully constrained sketch
     theStorage->refresh();
@@ -196,18 +197,29 @@ bool SketchSolver_Group::moveFeature(FeaturePtr theFeature,
                                      const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
                                      const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
 {
-  SolverConstraintPtr aConstraint =
-      move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked, theFeature, theFrom, theTo);
+  EntityWrapperPtr anEntity = myStorage->entity(theFeature);
+  SolverConstraintPtr aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+                                         theFeature, anEntity, theFrom, theTo);
   setTemporary(aConstraint);
   return true;
 }
 
 bool SketchSolver_Group::movePoint(AttributePtr theAttribute,
+                                   const int thePointIndex,
                                    const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
                                    const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
 {
-  SolverConstraintPtr aConstraint =
-      move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked, theAttribute, theFrom, theTo);
+  EntityWrapperPtr anEntity = myStorage->entity(theAttribute);
+  SolverConstraintPtr aConstraint;
+  if (thePointIndex < 0) {
+    aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+                       theAttribute, anEntity, theFrom, theTo);
+  }
+  else {
+    aConstraint = move(myStorage, mySketchSolver, myDOF, myIsEventsBlocked,
+                       std::pair<AttributePtr, int>(theAttribute, thePointIndex), anEntity,
+                       theFrom, theTo);
+  }
   setTemporary(aConstraint);
   return true;
 }
index 45407ddb8f47884f6dbc4efb5a4ede2d0a567a25..d5617155932ec56e073b7ed706b172f2641e7edf 100644 (file)
@@ -90,12 +90,14 @@ class SketchSolver_Group
                    const std::shared_ptr<GeomAPI_Pnt2d>& theTo);
   /** \brief Updates the data corresponding the specified point moved in GUI.
    *         Special kind of Fixed constraints is created.
-   *  \param[in] thePoint the attribute to be updated
-   *  \param[in] theFrom  start point of the movement
-   *  \param[in] theTo    final point of the movement
+   *  \param[in] thePointOrArray the attribute to be updated
+   *  \param[in] thePointIndex   index of moved point in array
+   *  \param[in] theFrom         start point of the movement
+   *  \param[in] theTo           destination point of the movement
    *  \return \c true, if the attribute is really moved
    */
-  bool movePoint(AttributePtr thePoint,
+  bool movePoint(AttributePtr thePointOrArray,
+                 const int thePointIndex,
                  const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
                  const std::shared_ptr<GeomAPI_Pnt2d>& theTo);
 
index a9d47533e95b12fb5cb18ad2dc632add3e8c13a5..b7b6d498036f4a8f64579d55cf8f56fb57eea235 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <Events_Loop.h>
 #include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
 #include <ModelAPI_Events.h>
 #include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Session.h>
@@ -87,6 +88,19 @@ static void featuresOrderedByType(const std::set<ObjectPtr>& theOriginalFeatures
   }
 }
 
+static void setPoint(AttributePtr theAttribute,
+                     const int thePointIndex,
+                     const std::shared_ptr<GeomAPI_Pnt2d> theValue)
+{
+  AttributePoint2DPtr aPointAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
+  AttributePoint2DArrayPtr aPointArrayAttr =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+  if (aPointAttr)
+    aPointAttr->setValue(theValue);
+  else if (aPointArrayAttr && thePointIndex >= 0)
+    aPointArrayAttr->setPnt(thePointIndex, theValue);
+}
+
 
 
 // ========================================================
@@ -180,8 +194,8 @@ void SketchSolver_Manager::processEvent(
         std::dynamic_pointer_cast<ModelAPI_ObjectMovedMessage>(theMessage);
 
     ObjectPtr aMovedObject = aMoveMsg->movedObject();
-    std::shared_ptr<GeomDataAPI_Point2D> aMovedPoint =
-        std::dynamic_pointer_cast<GeomDataAPI_Point2D>(aMoveMsg->movedAttribute());
+    AttributePtr aMovedAttribute = aMoveMsg->movedAttribute();
+    int aMovedPoint = aMoveMsg->movedPointIndex();
 
     const std::shared_ptr<GeomAPI_Pnt2d>& aFrom = aMoveMsg->originalPosition();
     const std::shared_ptr<GeomAPI_Pnt2d>& aTo = aMoveMsg->currentPosition();
@@ -192,8 +206,8 @@ void SketchSolver_Manager::processEvent(
           std::dynamic_pointer_cast<SketchPlugin_Feature>(aMovedFeature);
       if (aSketchFeature && !aSketchFeature->isMacro())
         needToResolve = moveFeature(aSketchFeature, aFrom, aTo);
-    } else if (aMovedPoint)
-      needToResolve = moveAttribute(aMovedPoint, aFrom, aTo);
+    } else if (aMovedAttribute)
+      needToResolve = moveAttribute(aMovedAttribute, aMovedPoint, aFrom, aTo);
 
   } else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_DELETED)) {
     std::shared_ptr<ModelAPI_ObjectDeletedMessage> aDeleteMsg =
@@ -349,7 +363,8 @@ bool SketchSolver_Manager::moveFeature(
 //  Purpose:  move given attribute in appropriate group
 // ============================================================================
 bool SketchSolver_Manager::moveAttribute(
-    const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
+    const std::shared_ptr<ModelAPI_Attribute>& theMovedAttribute,
+    const int theMovedPointIndex,
     const std::shared_ptr<GeomAPI_Pnt2d>& theFrom,
     const std::shared_ptr<GeomAPI_Pnt2d>& theTo)
 {
@@ -358,7 +373,7 @@ bool SketchSolver_Manager::moveAttribute(
       std::dynamic_pointer_cast<SketchPlugin_Constraint>(anOwner);
   if (aConstraint)
   {
-    theMovedAttribute->setValue(theTo);
+    setPoint(theMovedAttribute, theMovedPointIndex, theTo);
     Events_Loop::loop()->flush(Events_Loop::eventByName(EVENT_OBJECT_UPDATED));
     return true;
   }
@@ -369,12 +384,12 @@ bool SketchSolver_Manager::moveAttribute(
   if (aSketchFeature)
     aGroup = findGroup(aSketchFeature);
   if (!aGroup) {
-    theMovedAttribute->setValue(theTo);
+    setPoint(theMovedAttribute, theMovedPointIndex, theTo);
     return false;
   }
 
   aGroup->blockEvents(true);
-  return aGroup->movePoint(theMovedAttribute, theFrom, theTo);
+  return aGroup->movePoint(theMovedAttribute, theMovedPointIndex, theFrom, theTo);
 }
 
 // ============================================================================
index 78ddaefbb26c2d99811bb51d0462d4564519ace8..33aa152a513fefc54e4ab734f9afc366505396f2 100644 (file)
@@ -85,12 +85,14 @@ protected:
                    const std::shared_ptr<GeomAPI_Pnt2d>& theToPoint);
 
   /** \brief Move feature using its moved attribute
-   *  \param[in] theMovedAttribute dragged point attribute of sketch feature
-   *  \param[in] theFromPoint      original position of the moved point
-   *  \param[in] theToPoint        prefereble position (current position of the mouse)
+   *  \param[in] theMovedAttribute  dragged point (array of points) attribute of sketch feature
+   *  \param[in] theMovedPointIndex index of dragged point in an array (-1 otherwise)
+   *  \param[in] theFromPoint       original position of the moved point
+   *  \param[in] theToPoint         prefereble position (current position of the mouse)
    *  \return \c true if the attribute owner has been changed successfully
    */
-  bool moveAttribute(const std::shared_ptr<GeomDataAPI_Point2D>& theMovedAttribute,
+  bool moveAttribute(const std::shared_ptr<ModelAPI_Attribute>& theMovedAttribute,
+                     const int theMovedPointIndex,
                      const std::shared_ptr<GeomAPI_Pnt2d>& theFromPoint,
                      const std::shared_ptr<GeomAPI_Pnt2d>& theToPoint);