Salome HOME
Merge branch 'occ/shaper2smesh'
[modules/shaper.git] / src / SketchPlugin / SketchPlugin_MacroBSpline.cpp
index ee47982d88175055421338fdef9aeb9b0903662e..100e011e66d33cafc01038c3bd2fb92a1f68f393 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>
 #include <GeomAlgoAPI_EdgeBuilder.h>
 #include <GeomAlgoAPI_PointBuilder.h>
 
+#include <GeomAPI_BSpline2d.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
+/// Create internal coincidence constraint with B-spline pole
 static void createInternalConstraint(SketchPlugin_Sketch* theSketch,
                                      AttributePtr thePoint,
                                      AttributePtr theBSplinePoles,
@@ -60,10 +54,18 @@ static void createInternalConstraint(SketchPlugin_Sketch* theSketch,
 
 SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline()
   : SketchPlugin_SketchEntity(),
+    myDegree(3),
     myIsPeriodic(false)
 {
 }
 
+SketchPlugin_MacroBSpline::SketchPlugin_MacroBSpline(bool isPeriodic)
+  : SketchPlugin_SketchEntity(),
+    myDegree(3),
+    myIsPeriodic(isPeriodic)
+{
+}
+
 void SketchPlugin_MacroBSpline::initAttributes()
 {
   data()->addAttribute(POLES_ID(), GeomDataAPI_Point2DArray::typeId());
@@ -72,6 +74,8 @@ void SketchPlugin_MacroBSpline::initAttributes()
   data()->addAttribute(REF_POLES_ID(), ModelAPI_AttributeRefAttrList::typeId());
   ModelAPI_Session::get()->validators()->registerNotObligatory(getKind(), REF_POLES_ID());
 
+  data()->addAttribute(CONTROL_POLYGON_ID(), ModelAPI_AttributeBoolean::typeId());
+
   data()->addAttribute(AUXILIARY_ID(), ModelAPI_AttributeBoolean::typeId());
 }
 
@@ -79,16 +83,18 @@ 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);
+  if (boolean(CONTROL_POLYGON_ID())->value()) {
+    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
@@ -136,23 +142,54 @@ std::string SketchPlugin_MacroBSpline::processEvent(
 
 FeaturePtr SketchPlugin_MacroBSpline::createBSplineFeature()
 {
-  FeaturePtr aBSpline = sketch()->addFeature(SketchPlugin_BSpline::ID());
+  if (myKnots.empty() || myMultiplicities.empty())
+    getAISObject(AISObjectPtr()); // fill B-spline parameters
+
+  FeaturePtr aBSpline = sketch()->addFeature(
+      myIsPeriodic ? SketchPlugin_BSplinePeriodic::ID() : SketchPlugin_BSpline::ID());
+
+  aBSpline->integer(SketchPlugin_BSplineBase::DEGREE_ID())->setValue(myDegree);
 
   AttributePoint2DArrayPtr aPoles = std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(
-      aBSpline->attribute(SketchPlugin_BSpline::POLES_ID()));
+      aBSpline->attribute(SketchPlugin_BSplineBase::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());
+      aBSpline->data()->realArray(SketchPlugin_BSplineBase::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(
+  AttributeDoubleArrayPtr aKnots =
+      aBSpline->data()->realArray(SketchPlugin_BSplineBase::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_BSplineBase::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);
+
+  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));
+  }
+
+  aBSpline->boolean(SketchPlugin_SketchEntity::AUXILIARY_ID())->setValue(
       boolean(AUXILIARY_ID())->value());
 
   aBSpline->execute();
@@ -168,10 +205,14 @@ void SketchPlugin_MacroBSpline::createControlPolygon(FeaturePtr theBSpline,
   int aSize = aPoles->size();
   // poles
   for (int index = 0; index < aSize; ++index)
-    thePoles.push_back(createAuxiliaryPole(theBSpline, aPoles, index));
+    thePoles.push_back(createAuxiliaryPole(aPoles, index));
   // segments
   for (int index = 1; index < aSize; ++index)
-    createAuxiliarySegment(theBSpline, aPoles, index - 1, index);
+    createAuxiliarySegment(aPoles, index - 1, index);
+  if (myIsPeriodic) {
+    // additional segment to close the control polygon
+    createAuxiliarySegment(aPoles, aSize - 1, 0);
+  }
 }
 
 void SketchPlugin_MacroBSpline::constraintsForPoles(const std::list<FeaturePtr>& thePoles)
@@ -211,13 +252,14 @@ AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
       std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
   AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
 
+  if (aPolesArray->size() < 2)
+    return AISObjectPtr();
+
   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());
+  // convert poles to vertices and collect weights
+  std::list<GeomPnt2dPtr> aPoles2D;
+  std::list<double> aWeights;
   for (int anIndex = 0; anIndex < aPolesArray->size(); ++anIndex) {
     double aWeight = aWeightsArray->value(anIndex);
     if (aWeight < 1.e-10)
@@ -226,16 +268,29 @@ AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
     aWeights.push_back(aWeight);
 
     GeomPnt2dPtr aPole = aPolesArray->pnt(anIndex);
+    aPoles2D.push_back(aPole);
     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);
+  std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve;
+  try {
+    aBSplineCurve.reset(new GeomAPI_BSpline2d(aPoles2D, aWeights, myIsPeriodic));
+  } catch (...) {
+    // cannot build a B-spline curve
+    return AISObjectPtr();
+  }
+  GeomShapePtr anEdge =
+      GeomAlgoAPI_EdgeBuilder::bsplineOnPlane(aSketch->coordinatePlane(), aBSplineCurve);
   if (!anEdge)
     return AISObjectPtr();
 
+  // store transient parameters of B-spline curve
+  myDegree = aBSplineCurve->degree();
+  myKnots = aBSplineCurve->knots();
+  myMultiplicities = aBSplineCurve->mults();
+
   aShapes.push_back(anEdge);
   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aShapes);
 
@@ -254,17 +309,36 @@ AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
 
 // ==========================     Auxiliary functions    ===========================================
 
-FeaturePtr createAuxiliaryPole(FeaturePtr theBSpline,
-                               AttributePoint2DArrayPtr theBSplinePoles,
-                               const int thePoleIndex)
+void SketchPlugin_MacroBSpline::assignDefaultNameForAux(FeaturePtr theAuxFeature,
+                                                        AttributePoint2DArrayPtr theBSplinePoles,
+                                                        const int thePoleIndex1,
+                                                        const int thePoleIndex2)
+{
+  FeaturePtr aBSpline = ModelAPI_Feature::feature(theBSplinePoles->owner());
+
+  std::ostringstream aName;
+  aName << aBSpline->name();
+  if (theAuxFeature->getKind() == SketchPlugin_Point::ID())
+    aName << "_" << theBSplinePoles->id() << "_" << thePoleIndex1;
+  else
+    aName << "_segment_" << thePoleIndex1 << "_" << thePoleIndex2;
+
+  theAuxFeature->data()->setName(aName.str());
+  theAuxFeature->lastResult()->data()->setName(aName.str());
+}
+
+FeaturePtr SketchPlugin_MacroBSpline::createAuxiliaryPole(AttributePoint2DArrayPtr theBSplinePoles,
+                                                          const int thePoleIndex)
 {
+  FeaturePtr aBSpline = ModelAPI_Feature::feature(theBSplinePoles->owner());
+
   SketchPlugin_Sketch* aSketch =
-      std::dynamic_pointer_cast<SketchPlugin_Feature>(theBSpline)->sketch();
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(aBSpline)->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);
+  aPointFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(aBSpline);
 
   GeomPnt2dPtr aPole = theBSplinePoles->pnt(thePoleIndex);
 
@@ -273,11 +347,7 @@ FeaturePtr createAuxiliaryPole(FeaturePtr theBSpline,
   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());
+  assignDefaultNameForAux(aPointFeature, theBSplinePoles, thePoleIndex);
 
   // internal constraint to keep position of the point
   createInternalConstraint(aSketch, aCoord, theBSplinePoles, thePoleIndex);
@@ -285,18 +355,19 @@ FeaturePtr createAuxiliaryPole(FeaturePtr theBSpline,
   return aPointFeature;
 }
 
-void createAuxiliarySegment(FeaturePtr theBSpline,
-                            AttributePoint2DArrayPtr theBSplinePoles,
-                            const int thePoleIndex1,
-                            const int thePoleIndex2)
+void SketchPlugin_MacroBSpline::createAuxiliarySegment(AttributePoint2DArrayPtr theBSplinePoles,
+                                                       const int thePoleIndex1,
+                                                       const int thePoleIndex2)
 {
+  FeaturePtr aBSpline = ModelAPI_Feature::feature(theBSplinePoles->owner());
+
   SketchPlugin_Sketch* aSketch =
-    std::dynamic_pointer_cast<SketchPlugin_Feature>(theBSpline)->sketch();
+      std::dynamic_pointer_cast<SketchPlugin_Feature>(aBSpline)->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);
+  aLineFeature->reference(SketchPlugin_Point::PARENT_ID())->setValue(aBSpline);
 
   AttributePoint2DPtr aLineStart = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
     aLineFeature->attribute(SketchPlugin_Line::START_ID()));
@@ -307,11 +378,7 @@ void createAuxiliarySegment(FeaturePtr theBSpline,
   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());
+  assignDefaultNameForAux(aLineFeature, theBSplinePoles, thePoleIndex1, thePoleIndex2);
 
   // internal constraints to keep the segment position
   createInternalConstraint(aSketch, aLineStart, theBSplinePoles, thePoleIndex1);