Salome HOME
Implement possibility to add a pole to B-spline
authorazv <azv@opencascade.com>
Tue, 28 Jan 2020 12:55:44 +0000 (15:55 +0300)
committerazv <azv@opencascade.com>
Tue, 28 Jan 2020 13:26:10 +0000 (16:26 +0300)
src/GeomData/GeomData_Point2DArray.cpp
src/PartSet/PartSet_BSplineWidget.cpp
src/SketchPlugin/SketchPlugin_BSplineBase.cpp
src/SketchPlugin/SketchPlugin_BSplineBase.h
src/SketchPlugin/SketchPlugin_MacroBSpline.cpp
src/SketchPlugin/SketchPlugin_MacroBSpline.h
src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_AttributeBuilder.cpp
src/SketchSolver/SketchSolver_ConstraintCoincidence.cpp
src/SketchSolver/SketchSolver_ConstraintCoincidence.h

index 4f18c7f768fc54601bc6e6b3ed6afc20b224bfc7..198f91605772dc56eb2a31c40f86576e5b36ccb7 100644 (file)
@@ -77,8 +77,10 @@ void GeomData_Point2DArray::setSize(const int theSize)
   }
   else { // reset the old array
     if (aValuesSize) {
-      if (aValuesSize != myArray->Length()) { // old data is not keept, a new array is created
+      if (aValuesSize != myArray->Length()) { // old data is kept in the new array
         Handle(TColStd_HArray1OfReal) aNewArray = new TColStd_HArray1OfReal(0, aValuesSize - 1);
+        for (int anIndex = 0; anIndex < aValuesSize && anIndex <= myArray->Upper(); ++anIndex)
+          aNewArray->SetValue(anIndex, myArray->Value(anIndex));
         myArray->ChangeArray(aNewArray);
         owner()->data()->sendAttributeUpdated(this);
       }
index 43632faece916e636569422295d9895511578617..9ca97448d277b246ee80c4e46416c6441214cee0 100644 (file)
@@ -206,7 +206,11 @@ void PartSet_BSplineWidget::onAddPole()
     }
   }
   if (aFound) {
-    // TODO: add a new pole after found Id
+    // add a new pole after found Id
+    std::ostringstream anActionName;
+    anActionName << SketchPlugin_BSplineBase::ADD_POLE_ACTION_ID() << "#" << aId;
+    if (feature()->customAction(anActionName.str()))
+      updateObject(feature());
 
     restoreValueCustom();
   }
index e39dfe6d9d278f3a14fa7b3172136cbfc4af46e4..380887a64e41d5eaae3d223102943a2a129da4fa 100644 (file)
 //
 
 #include <SketchPlugin_BSplineBase.h>
+
+#include <SketchPlugin_ConstraintCoincidenceInternal.h>
+#include <SketchPlugin_Line.h>
+#include <SketchPlugin_MacroBSpline.h>
 #include <SketchPlugin_Sketch.h>
 
+#include <Events_InfoMessage.h>
+
 #include <GeomAlgoAPI_EdgeBuilder.h>
 
+#include <GeomAPI_BSpline2d.h>
 #include <GeomAPI_Pnt2d.h>
 
 #include <GeomDataAPI_Point2D.h>
 #include <GeomDataAPI_Point2DArray.h>
 
+#include <ModelAPI_AttributeDouble.h>
 #include <ModelAPI_AttributeDoubleArray.h>
 #include <ModelAPI_AttributeIntArray.h>
 #include <ModelAPI_AttributeInteger.h>
@@ -150,3 +158,130 @@ void SketchPlugin_BSplineBase::attributeChanged(const std::string& theID) {
 ////    }
   }
 }
+
+bool SketchPlugin_BSplineBase::customAction(const std::string& theActionId)
+{
+  // parse for the action and an index divided by '#'
+  std::string anAction;
+  int anIndex = -1;
+  size_t pos = theActionId.find('#');
+  if (pos != std::string::npos) {
+    anAction = theActionId.substr(0, pos);
+    anIndex = std::stoi(theActionId.substr(pos + 1));
+  }
+
+  if (anAction == ADD_POLE_ACTION_ID()) {
+    return addPole(anIndex);
+  }
+
+  std::string aMsg = "Error: Feature \"%1\" does not support action \"%2\".";
+  Events_InfoMessage("SketchPlugin_BSplineBase", aMsg).arg(getKind()).arg(anAction).send();
+  return false;
+}
+
+bool SketchPlugin_BSplineBase::addPole(const int theAfter)
+{
+  AttributePoint2DArrayPtr aPolesArray =
+      std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(attribute(POLES_ID()));
+  AttributeDoubleArrayPtr aWeightsArray = data()->realArray(WEIGHTS_ID());
+
+  int anAfter = (!isPeriodic() && theAfter == aPolesArray->size() - 1) ? theAfter - 1 : theAfter;
+
+  // find internal coincidences applied to the poles with greater indices
+  std::list<AttributeIntegerPtr> aCoincidentPoleIndex;
+  bool hasAuxSegment = false;
+  const std::set<AttributePtr>& aRefs = data()->refsToMe();
+  for (std::set<AttributePtr>::iterator anIt = aRefs.begin(); anIt != aRefs.end(); ++anIt) {
+    FeaturePtr aFeature = ModelAPI_Feature::feature((*anIt)->owner());
+    if (aFeature->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+      AttributeIntegerPtr anIndex;
+      if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A())
+        anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+      else if ((*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_B())
+        anIndex = aFeature->integer(SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+
+      if (anIndex && anIndex->isInitialized()) {
+        if (anIndex->value() > anAfter)
+          aCoincidentPoleIndex.push_back(anIndex);
+        else if (anIndex->value() == anAfter && !hasAuxSegment) {
+          // check the constrained object is a segment of the control polygon
+          const std::string& anOtherAttr =
+              (*anIt)->id() == SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A() ?
+                               SketchPlugin_ConstraintCoincidenceInternal::ENTITY_B() :
+                               SketchPlugin_ConstraintCoincidenceInternal::ENTITY_A();
+          AttributeRefAttrPtr aRefAttr = aFeature->refattr(anOtherAttr);
+          if (aRefAttr && !aRefAttr->isObject() &&
+              aRefAttr->attr()->id() == SketchPlugin_Line::START_ID()) {
+            hasAuxSegment = true;
+            aCoincidentPoleIndex.push_back(anIndex);
+          }
+        }
+      }
+    }
+  }
+
+  bool aWasBlocked = data()->blockSendAttributeUpdated(true);
+
+  // add new pole and default weight
+  std::list<GeomPnt2dPtr> aPoles;
+  aPolesArray->setSize(aPolesArray->size() + 1);
+  aPolesArray->setPnt(aPolesArray->size() - 1, aPolesArray->pnt(0)); // for periodic spline
+  for (int i = aPolesArray->size() - 2; i > anAfter; --i) {
+    aPoles.push_front(aPolesArray->pnt(i));
+    aPolesArray->setPnt(i + 1, aPoles.front());
+  }
+
+  GeomPnt2dPtr aCurPole = aPolesArray->pnt(anAfter);
+  GeomPnt2dPtr aNextPole = aPolesArray->pnt(anAfter + 1);
+  aPolesArray->setPnt(anAfter + 1, (aCurPole->x() + aNextPole->x()) * 0.5,
+                                   (aCurPole->y() + aNextPole->y()) * 0.5);
+  for (int i = anAfter + 1; i >= 0; --i)
+    aPoles.push_front(aPolesArray->pnt(i));
+
+  std::list<double> aWeights;
+  for (int i = 0; i < aWeightsArray->size(); ++i) {
+    aWeights.push_back(aWeightsArray->value(i));
+    if (i == anAfter)
+      aWeights.push_back(1.0); // default weight
+  }
+  aWeightsArray->setSize(aWeightsArray->size() + 1);
+  std::list<double>::iterator aWIt = aWeights.begin();
+  for (int i = 0; i < aWeightsArray->size(); ++i, ++aWIt)
+    aWeightsArray->setValue(i, *aWIt);
+
+  // recalculate knots and multiplicities
+  std::shared_ptr<GeomAPI_BSpline2d> aBSplineCurve(
+      new GeomAPI_BSpline2d(aPoles, aWeights, isPeriodic()));
+
+  integer(DEGREE_ID())->setValue(aBSplineCurve->degree());
+
+  AttributeDoubleArrayPtr aKnotsAttr = data()->realArray(SketchPlugin_BSplineBase::KNOTS_ID());
+  std::list<double> aKnots = aBSplineCurve->knots();
+  int aSize = (int)aKnots.size();
+  aKnotsAttr->setSize(aSize);
+  std::list<double>::iterator aKIt = aKnots.begin();
+  for (int index = 0; index < aSize; ++index, ++aKIt)
+    aKnotsAttr->setValue(index, *aKIt);
+
+  AttributeIntArrayPtr aMultsAttr = data()->intArray(SketchPlugin_BSplineBase::MULTS_ID());
+  std::list<int> aMults = aBSplineCurve->mults();
+  aSize = (int)aMults.size();
+  aMultsAttr->setSize(aSize);
+  std::list<int>::iterator aMIt = aMults.begin();
+  for (int index = 0; index < aSize; ++index, ++aMIt)
+    aMultsAttr->setValue(index, *aMIt);
+
+  data()->blockSendAttributeUpdated(aWasBlocked, true);
+
+  // update indices of internal coincidences
+  for (std::list<AttributeIntegerPtr>::iterator aCIt = aCoincidentPoleIndex.begin();
+       aCIt != aCoincidentPoleIndex.end(); ++aCIt)
+    (*aCIt)->setValue((*aCIt)->value() + 1);
+
+  // create auxiliary segment and pole updating the control polygon
+  SketchPlugin_MacroBSpline::createAuxiliaryPole(aPolesArray, anAfter + 1);
+  if (hasAuxSegment)
+    SketchPlugin_MacroBSpline::createAuxiliarySegment(aPolesArray, anAfter, anAfter + 1);
+
+  return true;
+}
index d84a17a9cff40c58c9552c7bab7d42d7e0e19020..fc75396af57a46991eee4491bfa386f59ef6d96b 100644 (file)
@@ -65,6 +65,13 @@ public:
     return ID;
   }
 
+  /// name for add pole action
+  inline static const std::string& ADD_POLE_ACTION_ID()
+  {
+    static const std::string ID("AddPole");
+    return ID;
+  }
+
   /// Returns true is sketch element is under the rigid constraint
   SKETCHPLUGIN_EXPORT virtual bool isFixed();
 
@@ -74,6 +81,11 @@ public:
   /// Creates a new part document if needed
   SKETCHPLUGIN_EXPORT virtual void execute();
 
+  /// Updates the B-spline curve.
+  /// \param[in] theActionId action key id (in following form: Action#Index)
+  /// \return \c false in case the action not performed.
+  SKETCHPLUGIN_EXPORT virtual bool customAction(const std::string& theActionId);
+
 protected:
   /// Called from the derived class
   SketchPlugin_BSplineBase();
@@ -83,6 +95,9 @@ protected:
 
   /// \brief Return \c true if the B-spline curve is periodic
   virtual bool isPeriodic() const = 0;
+
+  /// Add new pole after the pole with the given index
+  bool addPole(const int theAfter);
 };
 
 #endif
index a7591e3c5b8a019e994a8e605973b2edebb409fd..4f491fe2d9cd7470ef2651cf1445116c24035bc7 100644 (file)
 
 #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,
@@ -211,13 +202,13 @@ 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(theBSpline, aPoles, aSize - 1, 0);
+    createAuxiliarySegment(aPoles, aSize - 1, 0);
   }
 }
 
@@ -315,17 +306,18 @@ AISObjectPtr SketchPlugin_MacroBSpline::getAISObject(AISObjectPtr thePrevious)
 
 // ==========================     Auxiliary functions    ===========================================
 
-FeaturePtr createAuxiliaryPole(FeaturePtr theBSpline,
-                               AttributePoint2DArrayPtr theBSplinePoles,
-                               const int thePoleIndex)
+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);
 
@@ -336,7 +328,7 @@ FeaturePtr createAuxiliaryPole(FeaturePtr theBSpline,
   aPointFeature->execute();
 
   std::ostringstream aName;
-  aName << theBSpline->name() << "_" << theBSplinePoles->id() << "_" << thePoleIndex;
+  aName << aBSpline->name() << "_" << theBSplinePoles->id() << "_" << thePoleIndex;
   aPointFeature->data()->setName(aName.str());
   aPointFeature->lastResult()->data()->setName(aName.str());
 
@@ -346,18 +338,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()));
@@ -370,7 +363,7 @@ void createAuxiliarySegment(FeaturePtr theBSpline,
   aLineFeature->execute();
 
   std::ostringstream aName;
-  aName << theBSpline->name() << "_segment_" << thePoleIndex1 << "_" << thePoleIndex2;
+  aName << aBSpline->name() << "_segment_" << thePoleIndex1 << "_" << thePoleIndex2;
   aLineFeature->data()->setName(aName.str());
   aLineFeature->lastResult()->data()->setName(aName.str());
 
index 78ef86823877ee1ded1e063035f92f05f35ca459..860c34f9de67397db0a9205fdde1b0d76b7d5c69 100644 (file)
@@ -31,6 +31,8 @@
 class GeomAPI_Circ2d;
 class GeomAPI_Pnt2d;
 
+class GeomDataAPI_Point2DArray;
+
 /**\class SketchPlugin_MacroBSpline
  * \ingroup Plugins
  * \brief Feature for creation of the new B-spline in Sketch.
@@ -114,6 +116,16 @@ private:
   void createControlPolygon(FeaturePtr theBSpline, std::list<FeaturePtr>& thePoles);
   void constraintsForPoles(const std::list<FeaturePtr>& thePoles);
 
+  /// Create Point feature coincident with the B-spline pole
+  static FeaturePtr createAuxiliaryPole(std::shared_ptr<GeomDataAPI_Point2DArray> theBSplinePoles,
+                                        const int thePoleIndex);
+  /// Create segment between consequtive B-spline poles
+  static void createAuxiliarySegment(std::shared_ptr<GeomDataAPI_Point2DArray> theBSplinePoles,
+                                     const int thePoleIndex1,
+                                     const int thePoleIndex2);
+  friend class SketchPlugin_BSplineBase;
+
+private:
   std::list<double> myKnots;
   std::list<int> myMultiplicities;
   int myDegree;
index 3323048d406494dd26deb0b750ad1abc59989325..a446abc6693cae4d85b920ffa00d8632c13014ef 100644 (file)
@@ -218,9 +218,18 @@ bool PlaneGCSSolver_AttributeBuilder::updateAttribute(
 
     if (aWrapper->size() != anAttribute->size()) {
       std::vector<PointWrapperPtr> aPointsArray = aWrapper->array();
+      std::vector<PointWrapperPtr>::iterator aPos = aPointsArray.begin();
       while (anAttribute->size() > (int)aPointsArray.size()) {
         // add points to the middle of array
-        aPointsArray.insert(--aPointsArray.end(), createPoint(GeomPnt2dPtr(), myStorage));
+        GeomPnt2dPtr aValue;
+        for (; aPos != aPointsArray.end(); ++aPos) {
+          aValue = anAttribute->pnt(aPos - aPointsArray.begin());
+          if (aValue->distance(PlaneGCSSolver_Tools::point(*aPos)) > tolerance)
+            break;
+        }
+        int aShift = aPos - aPointsArray.begin();
+        aPointsArray.insert(aPos, createPoint(aValue, myStorage));
+        aPos = aPointsArray.begin() + aShift;
       }
 
       while (anAttribute->size() < (int)aPointsArray.size()) {
@@ -241,7 +250,7 @@ bool PlaneGCSSolver_AttributeBuilder::updateAttribute(
       aParamsToRemove = PlaneGCSSolver_Tools::parameters(aWrapper);
       std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> aNewArray =
           std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(
-          createAttribute(theAttribute));
+          createScalarArray(theAttribute, myStorage));
       aWrapper->setArray(aNewArray->array());
       isUpdated = true;
     }
index 990297396e2f99f5355e750b084388e26e2c9f77..c00dcfce8d1ccd609a33d9083c1e9d74fad0d69a 100644 (file)
@@ -339,3 +339,18 @@ void SketchSolver_ConstraintCoincidence::notify(const FeaturePtr&      theFeatur
     }
   }
 }
+
+void SketchSolver_ConstraintCoincidence::adjustConstraint()
+{
+  if (myBaseConstraint->getKind() == SketchPlugin_ConstraintCoincidenceInternal::ID()) {
+    AttributeIntegerPtr anIndexA = myBaseConstraint->integer(
+        SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_A());
+    AttributeIntegerPtr anIndexB = myBaseConstraint->integer(
+        SketchPlugin_ConstraintCoincidenceInternal::INDEX_ENTITY_B());
+    if ((anIndexA && anIndexA->isInitialized()) ||
+        (anIndexB && anIndexB->isInitialized())) {
+      remove();
+      process();
+    }
+  }
+}
index f520b75d0ef28aeef2519536719bcd2120fb758e..4ed2b821c7825e285eb503919ebe9d86eeaec565 100644 (file)
@@ -52,6 +52,10 @@ protected:
   virtual void getAttributes(EntityWrapperPtr&              theValue,
                              std::vector<EntityWrapperPtr>& theAttributes);
 
+  /// \brief This method is used in derived objects to check consistency of constraint.
+  ///        E.g. the distance between line and point may be signed.
+  virtual void adjustConstraint();
+
 protected:
   bool myInSolver; ///< shows the constraint is added to the solver
   EntityWrapperPtr myFeatureExtremities[2]; ///< extremities of a feature, a point is coincident to