]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Issue #17347: B-Splines in Sketcher
authorazv <azv@opencascade.com>
Thu, 23 Jan 2020 15:23:45 +0000 (18:23 +0300)
committerazv <azv@opencascade.com>
Thu, 23 Jan 2020 15:23:45 +0000 (18:23 +0300)
Implement periodic B-spline curves.

13 files changed:
src/GeomAPI/GeomAPI_BSpline2d.cpp
src/SketchPlugin/CMakeLists.txt
src/SketchPlugin/SketchPlugin_BSpline.cpp
src/SketchPlugin/SketchPlugin_BSplinePeriodic.cpp [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_BSplinePeriodic.h [new file with mode: 0644]
src/SketchPlugin/SketchPlugin_MacroBSpline.cpp
src/SketchPlugin/SketchPlugin_MacroBSpline.h
src/SketchPlugin/SketchPlugin_Plugin.cpp
src/SketchPlugin/plugin-Sketch.xml
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_FeatureBuilder.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Tools.cpp

index 58eb68580d5bfb585a2ac9f0e485b90a54f5cc6d..820d4cf15d338daf27dbaed320fd3eccc6ba4c82 100644 (file)
@@ -47,9 +47,13 @@ static Handle_Geom2d_BSplineCurve* newBSpline2d(
   if (theKnots.empty() || theMults.empty())
     return newBSpline2d(thePoles, theWeights, theDegree, thePeriodic);
 
+  int anAuxPole = 0;
+  if (thePeriodic && thePoles.front()->distance(thePoles.back()) > Precision::Confusion())
+    anAuxPole = 1;
+
   // collect arrays of poles, weights, knots and multiplicities
-  TColgp_Array1OfPnt2d aPoles(1, (int)thePoles.size());
-  TColStd_Array1OfReal aWeights(1, (int)theWeights.size());
+  TColgp_Array1OfPnt2d aPoles(1, (int)thePoles.size() + anAuxPole);
+  TColStd_Array1OfReal aWeights(1, (int)theWeights.size() + anAuxPole);
   TColStd_Array1OfReal aKnots(1, (int)theKnots.size());
   TColStd_Array1OfInteger aMults(1, (int)theMults.size());
 
@@ -70,6 +74,11 @@ static Handle_Geom2d_BSplineCurve* newBSpline2d(
        aMIt != theMults.end(); ++aMIt, ++anIndex)
     aMults.SetValue(anIndex, *aMIt);
 
+  if (thePeriodic) {
+    aPoles.ChangeLast() = aPoles.First();
+    aWeights.ChangeLast() = aWeights.First();
+  }
+
   Handle(Geom2d_BSplineCurve) aCurve =
       new Geom2d_BSplineCurve(aPoles, aWeights, aKnots, aMults, theDegree, thePeriodic);
   return new Handle_Geom2d_BSplineCurve(aCurve);
@@ -81,7 +90,21 @@ Handle_Geom2d_BSplineCurve* newBSpline2d(
     const int theDegree,
     const bool thePeriodic)
 {
+  std::list<std::shared_ptr<GeomAPI_Pnt2d> > aPoles = thePoles;
+  std::list<double> aWeights = theWeights;
+  int aMult = theDegree + 1;
   int aNbKnots = (int)thePoles.size() - theDegree + 1;
+  if (thePeriodic) {
+    if (aPoles.front()->distance(aPoles.back()) < Precision::Confusion()) {
+      aPoles.pop_back();
+      aWeights.pop_back();
+    }
+    aPoles.push_back(aPoles.front());
+    aWeights.push_back(aWeights.front());
+    aMult = 1;
+    aNbKnots = (int)aPoles.size() + 1;
+  }
+
   if (aNbKnots < 2)
     return new Handle_Geom2d_BSplineCurve();
 
@@ -95,10 +118,10 @@ Handle_Geom2d_BSplineCurve* newBSpline2d(
   aKnots.push_back(aEndParam);
 
   std::list<int> aMults(aNbKnots - 2, 1);
-  aMults.push_front(theDegree + 1);
-  aMults.push_back(theDegree + 1);
+  aMults.push_front(aMult);
+  aMults.push_back(aMult);
 
-  return newBSpline2d(thePoles, theWeights, aKnots, aMults, theDegree, thePeriodic);
+  return newBSpline2d(aPoles, aWeights, aKnots, aMults, theDegree, thePeriodic);
 }
 
 static Handle_Geom2d_BSplineCurve* newBSpline2d(
index 8063b10ca867b4fed2c0ff79012c7b5c61abe104..9855c5f4ca4e87ed3e1d0df3666e5a34bf2d2e28 100644 (file)
@@ -24,6 +24,7 @@ SET(PROJECT_HEADERS
     SketchPlugin.h
     SketchPlugin_Arc.h
     SketchPlugin_BSpline.h
+    SketchPlugin_BSplinePeriodic.h
     SketchPlugin_Circle.h
     SketchPlugin_Constraint.h
     SketchPlugin_ConstraintAngle.h
@@ -76,6 +77,7 @@ SET(PROJECT_HEADERS
 SET(PROJECT_SOURCES
     SketchPlugin_Arc.cpp
     SketchPlugin_BSpline.cpp
+    SketchPlugin_BSplinePeriodic.cpp
     SketchPlugin_Circle.cpp
     SketchPlugin_Constraint.cpp
     SketchPlugin_ConstraintAngle.cpp
index f4aee05a9b67eef678f130a338e1f45148f7cf5d..a56d5281a0e8a18b5902510fae0a2f426d4d0531 100644 (file)
@@ -160,6 +160,4 @@ void SketchPlugin_BSpline::attributeChanged(const std::string& theID) {
     std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
         attribute(END_ID()))->setValue(aPolesArray->pnt(aPolesArray->size() - 1));
   }
-////  else if (theID == REVERSED_ID() && myParamDelta == 0.0)
-////    myParamDelta = 2.0 * PI;
 }
diff --git a/src/SketchPlugin/SketchPlugin_BSplinePeriodic.cpp b/src/SketchPlugin/SketchPlugin_BSplinePeriodic.cpp
new file mode 100644 (file)
index 0000000..a20ec2a
--- /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_BSplinePeriodic.h>
+#include <SketchPlugin_Sketch.h>
+
+#include <GeomAlgoAPI_EdgeBuilder.h>
+
+#include <GeomAPI_Pnt2d.h>
+
+#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeIntArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_Validator.h>
+
+
+SketchPlugin_BSplinePeriodic::SketchPlugin_BSplinePeriodic()
+  : SketchPlugin_SketchEntity()
+{
+}
+
+void SketchPlugin_BSplinePeriodic::initDerivedClassAttributes()
+{
+  data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
+  data()->addAttribute(WEIGHTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
+  data()->addAttribute(KNOTS_ID(), ModelAPI_AttributeDoubleArray::typeId());
+  data()->addAttribute(MULTS_ID(), ModelAPI_AttributeIntArray::typeId());
+  data()->addAttribute(DEGREE_ID(), ModelAPI_AttributeInteger::typeId());
+
+  data()->addAttribute(EXTERNAL_ID(), ModelAPI_AttributeSelection::typeId());
+  ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), EXTERNAL_ID());
+}
+
+void SketchPlugin_BSplinePeriodic::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());
+  AttributeDoubleArrayPtr aKnotsArray = data()->realArray(KNOTS_ID());
+  AttributeIntArrayPtr aMultsArray = data()->intArray(MULTS_ID());
+  AttributeIntegerPtr aDegreeAttr = data()->integer(DEGREE_ID());
+
+  // collect poles
+  std::list<GeomPnt2dPtr> aPoles2D;
+  for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
+    GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+    aPoles2D.push_back(aPole);
+  }
+  // collect weights
+  std::list<double> aWeights;
+  for (int anIndex = 0; anIndex < aWeightsArray->size(); ++anIndex)
+    aWeights.push_back(aWeightsArray->value(anIndex));
+  // collect knots
+  std::list<double> aKnots;
+  for (int anIndex = 0; anIndex < aKnotsArray->size(); ++anIndex)
+    aKnots.push_back(aKnotsArray->value(anIndex));
+  // collect multiplicities
+  std::list<int> aMults;
+  for (int anIndex = 0; anIndex < aMultsArray->size(); ++anIndex)
+    aMults.push_back(aMultsArray->value(anIndex));
+
+  // create result non-periodic B-spline curve
+  GeomShapePtr anEdge = GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->coordinatePlane(),
+      aPoles2D, aWeights, aKnots, aMults, aDegreeAttr->value(), true);
+
+  ResultConstructionPtr aResult = document()->createConstruction(data(), 0);
+  aResult->setShape(anEdge);
+  aResult->setIsInHistory(false);
+  setResult(aResult, 0);
+}
+
+bool SketchPlugin_BSplinePeriodic::isFixed() {
+  return data()->selection(EXTERNAL_ID())->context().get() != NULL;
+}
+
+void SketchPlugin_BSplinePeriodic::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();
+////    }
+  }
+}
diff --git a/src/SketchPlugin/SketchPlugin_BSplinePeriodic.h b/src/SketchPlugin/SketchPlugin_BSplinePeriodic.h
new file mode 100644 (file)
index 0000000..80e6bfa
--- /dev/null
@@ -0,0 +1,99 @@
+// 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_BSplinePeriodic_H_
+#define SketchPlugin_BSplinePeriodic_H_
+
+#include <SketchPlugin.h>
+#include <SketchPlugin_SketchEntity.h>
+
+/**\class SketchPlugin_BSplinePeriodic
+ * \ingroup Plugins
+ * \brief Feature for creation of the periodic B-spline curve in the sketch.
+ */
+class SketchPlugin_BSplinePeriodic : public SketchPlugin_SketchEntity
+{
+public:
+  /// Ellipse feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchBSplinePeriodic");
+    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;
+  }
+
+  /// attribute to store the degree of B-spline
+  inline static const std::string& DEGREE_ID()
+  {
+    static const std::string ID("degree");
+    return ID;
+  }
+
+  /// list of B-spline knots
+  inline static const std::string& KNOTS_ID()
+  {
+    static const std::string ID("knots");
+    return ID;
+  }
+
+  /// list of B-spline multiplicities
+  inline static const std::string& MULTS_ID()
+  {
+    static const std::string ID("multiplicities");
+    return ID;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    static std::string MY_KIND = SketchPlugin_BSplinePeriodic::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_BSplinePeriodic();
+
+protected:
+  /// \brief Initializes attributes of derived class.
+  virtual void initDerivedClassAttributes();
+};
+
+#endif
index 28200494663ca0d248c31f3a55e9e85c156f042f..5f325dedfd9c55151618b9b839a241f3d6aff70b 100644 (file)
@@ -20,6 +20,7 @@
 #include <SketchPlugin_MacroBSpline.h>
 
 #include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
 #include <SketchPlugin_ConstraintCoincidenceInternal.h>
 #include <SketchPlugin_Line.h>
 #include <SketchPlugin_Point.h>
@@ -67,6 +68,13 @@ SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline()
 {
 }
 
+SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline(bool isPeriodic)
+  : SketchPlugin_SketchEntity(),
+    myDegree(3),
+    myIsPeriodic(isPeriodic)
+{
+}
+
 void SketchPlugin_MacroBSpline::initAttributes()
 {
   data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
@@ -143,52 +151,55 @@ std::string SketchPlugin_MacroBSpline::processEvent(
 
 FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature()
 {
-  FeaturePtr aBSpline = sketch()->addFeature(SketchPlugin_BSpline::ID());
+  FeaturePtr aBSpline = sketch()->addFeature(
+      myIsPeriodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
 
-  aBSpline->integer(SketchPlugin_BSpline::DEGREE_ID())->setValue(myDegree);
+  aBSpline->integer(myIsPeriodic ? SketchPlugin_BSplinePeriodic::DEGREE_ID()
+                                 : SketchPlugin_BSpline::DEGREE_ID())->setValue(myDegree);
 
   AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
-      aBSpline->attribute(SketchPlugin_BSpline::POLES_ID()));
+      aBSpline->attribute(myIsPeriodic ? SketchPlugin_BSplinePeriodic::POLES_ID()
+                                       : 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 aWeights = aBSpline->data()->realArray(
+      myIsPeriodic ? SketchPlugin_BSplinePeriodic::WEIGHTS_ID()
+                   : 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));
 
-  AttributeDoubleArrayPtr aKnots =
-      aBSpline->data()->realArray(SketchPlugin_BSpline::KNOTS_ID());
+  AttributeDoubleArrayPtr aKnots = aBSpline->data()->realArray(
+      myIsPeriodic ? SketchPlugin_BSplinePeriodic::KNOTS_ID() : SketchPlugin_BSpline::KNOTS_ID());
   aSize = (int)myKnots.size();
   aKnots->setSize(aSize);
   std::list<double>::iterator aKIt = myKnots.begin();
   for (int index = 0; index < aSize; ++index, ++aKIt)
     aKnots->setValue(index, *aKIt);
 
-  AttributeIntArrayPtr aMults =
-      aBSpline->data()->intArray(SketchPlugin_BSpline::MULTS_ID());
+  AttributeIntArrayPtr aMults = aBSpline->data()->intArray(
+      myIsPeriodic ? SketchPlugin_BSplinePeriodic::MULTS_ID() : SketchPlugin_BSpline::MULTS_ID());
   aSize = (int)myMultiplicities.size();
   aMults->setSize(aSize);
   std::list<int>::iterator aMIt = myMultiplicities.begin();
   for (int index = 0; index < aSize; ++index, ++aMIt)
     aMults->setValue(index, *aMIt);
 
-  SketchPlugin_Sketch* aSketch =
-      std::dynamic_pointer_cast<SketchPlugin_Feature>(aBSpline)->sketch();
-
-  AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aBSpline->attribute(SketchPlugin_BSpline::START_ID()));
-  aStartPoint->setValue(aPoles->pnt(0));
+  if (!myIsPeriodic) {
+    AttributePoint2DPtr aStartPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+        aBSpline->attribute(SketchPlugin_BSpline::START_ID()));
+    aStartPoint->setValue(aPoles->pnt(0));
 
-  AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
-      aBSpline->attribute(SketchPlugin_BSpline::END_ID()));
-  aEndPoint->setValue(aPoles->pnt(aPoles->size() - 1));
+    AttributePoint2DPtr aEndPoint = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
+       aBSpline->attribute(SketchPlugin_BSpline::END_ID()));
+    aEndPoint->setValue(aPoles->pnt(aPoles->size() - 1));
+  }
 
-  aBSpline->boolean(SketchPlugin_BSpline::AUXILIARY_ID())->setValue(
+  aBSpline->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
       boolean(AUXILIARY_ID())->value());
 
   aBSpline->execute();
@@ -208,6 +219,10 @@ void SketchPlugin_MacroBSpline::createControlPolygon(FeaturePtr theBSpline,
   // segments
   for (int index = 1; index < aSize; ++index)
     createAuxiliarySegment(theBSpline, aPoles, index - 1, index);
+  if (myIsPeriodic) {
+    // additional segment to close the control polygon
+    createAuxiliarySegment(theBSpline, aPoles, aSize - 1, 0);
+  }
 }
 
 void SketchPlugin_MacroBSpline::constraintsForPoles(const std::list<FeaturePtr>& thePoles)
@@ -243,8 +258,6 @@ AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
   if (!aSketch)
     return AISObjectPtr();
 
-  static const bool PERIODIC = false;
-
   AttributePoint2DArrayPtr aPolesArray =
       std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
   AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
@@ -273,7 +286,7 @@ AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
   // create result non-periodic B-spline curve
   std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve;
   try {
-    aBSplineCurve.reset(new GeomAPI_BSpline2d(aPoles2D, aWeights, PERIODIC));
+    aBSplineCurve.reset(new GeomAPI_BSpline2d(aPoles2D, aWeights, myIsPeriodic));
   } catch (...) {
     // cannot build a B-spline curve
     return AISObjectPtr();
index d8a0e5b89d5cdc20282c099485ed3f7794f8745d..78ef86823877ee1ded1e063035f92f05f35ca459 100644 (file)
@@ -105,6 +105,9 @@ public:
   /// Use plugin manager for features creation
   SketchPlugin_MacroBSpline();
 
+protected:
+  SketchPlugin_MacroBSpline(bool isPeriodic);
+
 private:
   FeaturePtr createBSplineFeature();
 
@@ -117,4 +120,29 @@ private:
   bool myIsPeriodic;
 };
 
+
+/**\class SketchPlugin_MacroBSpline
+* \ingroup Plugins
+* \brief Feature for creation of the new B-spline in Sketch.
+*/
+class SketchPlugin_MacroBSplinePeriodic : public SketchPlugin_MacroBSpline
+{
+public:
+  /// B-spline macro feature kind
+  inline static const std::string& ID()
+  {
+    static const std::string ID("SketchMacroBSplinePeriodic");
+    return ID;
+  }
+
+  /// Returns the kind of a feature
+  SKETCHPLUGIN_EXPORT virtual const std::string& getKind()
+  {
+    return SketchPlugin_MacroBSpline::ID();
+  }
+
+  /// Use plugin manager for features creation
+  SketchPlugin_MacroBSplinePeriodic() : SketchPlugin_MacroBSpline(true) {}
+};
+
 #endif
index a6ef2a190e47f0960eb2964d3baeba18325a8b2c..db8995277246a8b5f079cea9fa7ac79e91e4e247 100644 (file)
@@ -25,6 +25,7 @@
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
 #include <SketchPlugin_Projection.h>
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
@@ -207,6 +208,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_Arc);
   } else if (theFeatureID == SketchPlugin_BSpline::ID()) {
     return FeaturePtr(new SketchPlugin_BSpline);
+  } else if (theFeatureID == SketchPlugin_BSplinePeriodic::ID()) {
+    return FeaturePtr(new SketchPlugin_BSplinePeriodic);
   } else if (theFeatureID == SketchPlugin_Projection::ID()) {
     return FeaturePtr(new SketchPlugin_Projection);
   } else if (theFeatureID == SketchPlugin_ConstraintCoincidence::ID()) {
@@ -259,6 +262,8 @@ FeaturePtr SketchPlugin_Plugin::createFeature(std::string theFeatureID)
     return FeaturePtr(new SketchPlugin_MacroArc);
   } else if (theFeatureID == SketchPlugin_MacroBSpline::ID()) {
     return FeaturePtr(new SketchPlugin_MacroBSpline);
+  } else if (theFeatureID == SketchPlugin_MacroBSplinePeriodic::ID()) {
+    return FeaturePtr(new SketchPlugin_MacroBSplinePeriodic);
   } else if (theFeatureID == SketchPlugin_MacroCircle::ID()) {
     return FeaturePtr(new SketchPlugin_MacroCircle);
   } else if (theFeatureID == SketchPlugin_Ellipse::ID()) {
@@ -315,6 +320,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_Circle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Arc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_BSpline::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_BSplinePeriodic::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Ellipse::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_EllipticArc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_Projection::ID(), aHasSketchPlane);
@@ -341,6 +347,7 @@ std::shared_ptr<ModelAPI_FeatureStateMessage> SketchPlugin_Plugin
       aMsg->setState(SketchPlugin_Trim::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroArc::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroBSpline::ID(), aHasSketchPlane);
+      aMsg->setState(SketchPlugin_MacroBSplinePeriodic::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroCircle::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroEllipse::ID(), aHasSketchPlane);
       aMsg->setState(SketchPlugin_MacroEllipticArc::ID(), aHasSketchPlane);
index 368f3d6029649539cc33ada5e70a121ec8cf00b9..c055b33102043647b8b1a5b71e997eaad9799e79 100644 (file)
@@ -6,7 +6,7 @@
         nested="SketchPoint SketchIntersectionPoint SketchLine
                 SketchCircle SketchMacroCircle SketchArc SketchMacroArc
                 SketchEllipse SketchMacroEllipse SketchEllipticArc SketchMacroEllipticArc
-                SketchBSpline SketchMacroBSpline
+                SketchBSpline SketchMacroBSpline SketchMacroBSplinePeriodic
                 SketchRectangle
                 SketchProjection
                 SketchConstraintLength SketchConstraintRadius SketchConstraintDistance SketchConstraintDistanceHorizontal SketchConstraintDistanceVertical
                    change_visual_attributes="true"/>
       </feature>
 
+      <!-- SketchBSplinePeriodic is a hidden feature. It is created inside SketchMacroBSplinePeriodic. -->
+      <feature id="SketchBSplinePeriodic"
+               title="Periodic B-spline"
+               tooltip="Create periodic B-spline curve"
+               icon="icons/Sketch/bspline_p.png"
+               helpfile="bsplineFeature.html"
+               internal="1">
+        <bspline-panel id="poles"
+                       weights="weights"
+                       title="Poles and weights"
+                       tooltip="B-spline poles and weights"
+                       enable_value="enable_by_preferences">
+          <validator id="SketchPlugin_BSplineValidator"/>
+        </bspline-panel>
+        <boolvalue id="Auxiliary"
+                   label="Auxiliary"
+                   default="false"
+                   tooltip="Construction element"
+                   obligatory="0"
+                   change_visual_attributes="true"/>
+      </feature>
+
       <!-- SketchMacroBSpline -->
       <feature id="SketchMacroBSpline"
                title="B-spline"
                    obligatory="0"
                    change_visual_attributes="true"/>
       </feature>
+
+      <!-- SketchMacroBSplinePeriodic -->
+      <feature id="SketchMacroBSplinePeriodic"
+               title="Periodic B-spline"
+               tooltip="Create periodic B-spline curve"
+               icon="icons/Sketch/bspline_p.png"
+               helpfile="bsplineFeature.html">
+        <sketch-bspline_selector id="poles"
+                                 weights="weights"
+                                 reference_attribute="poles_ref"
+                                 title="Poles and weights"
+                                 tooltip="B-spline poles and weights"
+                                 enable_value="enable_by_preferences">
+          <validator id="SketchPlugin_BSplineValidator"/>
+        </sketch-bspline_selector>
+        <boolvalue id="need_control_poly"
+                   label="Create control polygon"
+                   default="true"
+                   tooltip="Specify if the control polygon should be created"/>
+        <boolvalue id="Auxiliary"
+                   label="Auxiliary"
+                   default="false"
+                   tooltip="Construction element"
+                   obligatory="0"
+                   change_visual_attributes="true"/>
+      </feature>
     </group>
 
     <group id="Segmentation">
index 24659d40681c0a562ca0c1616bfb3ed6898d1e47..988a3c5a4d676b6e1a9041d7053dc44b98e2c79f 100644 (file)
@@ -33,6 +33,7 @@
 #include <ModelAPI_AttributeDoubleArray.h>
 #include <ModelAPI_AttributeInteger.h>
 #include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_MultiRotation.h>
 
@@ -88,8 +89,10 @@ static EntityWrapperPtr createScalar(const AttributePtr&     theAttribute,
      (theAttribute->id() == SketchPlugin_MultiRotation::ANGLE_ID() &&
       anOwner->getKind() == SketchPlugin_MultiRotation::ID()))
     aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_AngleWrapper(createParameter(theStorage)));
-  else if (anOwner->getKind() == SketchPlugin_BSpline::ID() &&
-           theAttribute->id() == SketchPlugin_BSpline::DEGREE_ID())
+  else if ((anOwner->getKind() == SketchPlugin_BSpline::ID() &&
+            theAttribute->id() == SketchPlugin_BSpline::DEGREE_ID()) ||
+           (anOwner->getKind() == SketchPlugin_BSplinePeriodic::ID() &&
+            theAttribute->id() == SketchPlugin_BSplinePeriodic::DEGREE_ID()))
     // Degree of B-spline is not processed by the solver
     aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(nullptr)));
   else
@@ -99,6 +102,13 @@ static EntityWrapperPtr createScalar(const AttributePtr&     theAttribute,
   return aWrapper;
 }
 
+template <typename TYPE>
+static bool nonSolverAttribute(const FeaturePtr theOwner, const std::string& theAttrId)
+{
+  return theOwner->getKind() == TYPE::ID() && (theAttrId == TYPE::WEIGHTS_ID()
+      || theAttrId == TYPE::KNOTS_ID() || theAttrId == TYPE::MULTS_ID());
+}
+
 static EntityWrapperPtr createScalarArray(const AttributePtr&     theAttribute,
                                           PlaneGCSSolver_Storage* theStorage)
 {
@@ -110,10 +120,8 @@ static EntityWrapperPtr createScalarArray(const AttributePtr&     theAttribute,
   PlaneGCSSolver_Storage* aStorage = theStorage;
   // Weights, knots and multiplicities of B-spline curve are not processed by the solver
   FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
-  if (anOwner->getKind() == SketchPlugin_BSpline::ID() &&
-      (theAttribute->id() == SketchPlugin_BSpline::WEIGHTS_ID() ||
-       theAttribute->id() == SketchPlugin_BSpline::KNOTS_ID() ||
-       theAttribute->id() == SketchPlugin_BSpline::MULTS_ID()))
+  if (nonSolverAttribute<SketchPlugin_BSpline>(anOwner, theAttribute->id()) ||
+      nonSolverAttribute<SketchPlugin_BSplinePeriodic>(anOwner, theAttribute->id()))
     aStorage = 0;
 
   int aSize = anArray.size();
index 8db97df1a3ea32ba9bd78dc4c4fdb71c68bd7743..e797abad2342bb7f6207dc48d1e65bfcb2a8ef3c 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_Ellipse.h>
 #include <SketchPlugin_EllipticArc.h>
@@ -48,6 +49,7 @@ static EntityWrapperPtr createArc(const AttributeEntityMap&    theAttributes,
 static EntityWrapperPtr createEllipse(const AttributeEntityMap& theAttributes);
 static EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
                                           PlaneGCSSolver_Storage*   theStorage);
+template <typename TYPE>
 static EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes);
 
 
@@ -107,7 +109,9 @@ EntityWrapperPtr PlaneGCSSolver_FeatureBuilder::createFeature(FeaturePtr theFeat
     aResult = createEllipticArc(myAttributes, myStorage);
   // B-spline curve
   else if (aFeatureKind == SketchPlugin_BSpline::ID())
-    aResult = createBSpline(myAttributes);
+    aResult = createBSpline<SketchPlugin_BSpline>(myAttributes);
+  else if (aFeatureKind == SketchPlugin_BSplinePeriodic::ID())
+    aResult = createBSpline<SketchPlugin_BSplinePeriodic>(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()) {
@@ -294,19 +298,20 @@ EntityWrapperPtr createEllipticArc(const AttributeEntityMap& theAttributes,
   return anEllipseWrapper;
 }
 
+template <typename TYPE>
 EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
 {
   std::shared_ptr<GCS::BSplineImpl> aNewSpline(new GCS::BSplineImpl);
 
   aNewSpline->degree = 3;
-  aNewSpline->periodic = false;
+  aNewSpline->periodic = std::is_same<TYPE, SketchPlugin_BSplinePeriodic>();
 
   std::map<std::string, EntityWrapperPtr> anAdditionalAttributes;
 
   AttributeEntityMap::const_iterator anIt = theAttributes.begin();
   for (; anIt != theAttributes.end(); ++anIt) {
     const std::string& anAttrID = anIt->first->id();
-    if (anAttrID == SketchPlugin_BSpline::POLES_ID()) {
+    if (anAttrID == TYPE::POLES_ID()) {
       PointArrayWrapperPtr anArray =
           std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
 
@@ -318,7 +323,7 @@ EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
       aNewSpline->start = aNewSpline->poles.front();
       aNewSpline->end = aNewSpline->poles.back();
     }
-    else if (anAttrID == SketchPlugin_BSpline::DEGREE_ID()) {
+    else if (anAttrID == TYPE::DEGREE_ID()) {
       ScalarWrapperPtr aScalar =
           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
       aNewSpline->degree = (int)aScalar->value();
@@ -330,11 +335,11 @@ EntityWrapperPtr createBSpline(const AttributeEntityMap& theAttributes)
     else {
       ScalarArrayWrapperPtr anArray =
           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
-      if (anAttrID == SketchPlugin_BSpline::WEIGHTS_ID())
+      if (anAttrID == TYPE::WEIGHTS_ID())
         aNewSpline->weights = anArray->array();
-      else if (anAttrID == SketchPlugin_BSpline::KNOTS_ID())
+      else if (anAttrID == TYPE::KNOTS_ID())
         aNewSpline->knots = anArray->array();
-      else if (anAttrID == SketchPlugin_BSpline::MULTS_ID()) {
+      else if (anAttrID == TYPE::MULTS_ID()) {
         const GCS::VEC_pD& aValues = anArray->array();
         aNewSpline->mult.reserve(aValues.size());
         for (GCS::VEC_pD::const_iterator anIt = aValues.begin(); anIt != aValues.end(); ++anIt)
index c190ae1b9cbcbff66bbfda51d2a39ddc020936af..2605ddf931a8b2a6ed5785ccb51a5de733e04c5c 100644 (file)
@@ -378,6 +378,8 @@ static void createBSplineConstraints(
   EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theCurve);
   std::shared_ptr<GCS::BSpline> aBSpline =
       std::dynamic_pointer_cast<GCS::BSpline>(anEdge->entity());
+  if (aBSpline->periodic)
+    return; // additional constraints are not necessary
 
   std::list<GCSConstraintPtr> aBSplineConstraints;
 
index 939b7a2636998d52522af328d8b0d168aeede0f5..e29d23018fba251e44f77bb27672d4e8e695456d 100644 (file)
@@ -43,6 +43,7 @@
 
 #include <SketchPlugin_Arc.h>
 #include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
 #include <SketchPlugin_Circle.h>
 #include <SketchPlugin_ConstraintAngle.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
@@ -483,6 +484,13 @@ bool PlaneGCSSolver_Tools::isAttributeApplicable(const std::string& theAttrName,
            theAttrName == SketchPlugin_BSpline::START_ID() ||
            theAttrName == SketchPlugin_BSpline::END_ID();
   }
+  else if (theOwnerName == SketchPlugin_BSplinePeriodic::ID()) {
+    return theAttrName == SketchPlugin_BSplinePeriodic::POLES_ID() ||
+           theAttrName == SketchPlugin_BSplinePeriodic::WEIGHTS_ID() ||
+           theAttrName == SketchPlugin_BSplinePeriodic::KNOTS_ID() ||
+           theAttrName == SketchPlugin_BSplinePeriodic::MULTS_ID() ||
+           theAttrName == SketchPlugin_BSplinePeriodic::DEGREE_ID();
+  }
 
   // suppose that all remaining features are points
   return theAttrName == SketchPlugin_Point::COORD_ID();