Salome HOME
Merge branch 'master' into occ/bsplines
[modules/shaper.git] / src / SketchSolver / PlaneGCSSolver / PlaneGCSSolver_AttributeBuilder.cpp
index bce4d90d627523ce8debaf1e6a26df40cbd58d2a..a446abc6693cae4d85b920ffa00d8632c13014ef 100644 (file)
@@ -24,6 +24,7 @@
 #include <PlaneGCSSolver_ScalarWrapper.h>
 #include <PlaneGCSSolver_ScalarArrayWrapper.h>
 #include <PlaneGCSSolver_BooleanWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
 
 #include <GeomAPI_Pnt2d.h>
 #include <GeomDataAPI_Point2D.h>
@@ -32,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>
 
@@ -87,8 +89,9 @@ 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() ||
+            anOwner->getKind() == SketchPlugin_BSplinePeriodic::ID()) &&
+           theAttribute->id() == SketchPlugin_BSplineBase::DEGREE_ID())
     // Degree of B-spline is not processed by the solver
     aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(nullptr)));
   else
@@ -98,36 +101,17 @@ 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)
 {
-  class ArrayAttribute {
-  public:
-    ArrayAttribute(AttributePtr theAttribute)
-    {
-      myDouble = std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(theAttribute);
-      myInteger = std::dynamic_pointer_cast<ModelAPI_AttributeIntArray>(theAttribute);
-    }
-
-    bool isInitialized() const
-    {
-      return (myDouble && myDouble->isInitialized()) || (myInteger && myInteger->isInitialized());
-    }
-
-    int size() const
-    {
-      return myDouble.get() ? myDouble->size() : myInteger->size();
-    }
-
-    double value(const int theIndex) const
-    {
-      return myDouble.get() ? myDouble->value(theIndex) : myInteger->value(theIndex);
-    }
-
-  private:
-    AttributeDoubleArrayPtr myDouble;
-    AttributeIntArrayPtr myInteger;
-  } anArray(theAttribute);
+  PlaneGCSSolver_Tools::AttributeArray anArray(theAttribute);
 
   if (!anArray.isInitialized())
     return EntityWrapperPtr();
@@ -135,10 +119,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();
@@ -220,3 +202,68 @@ EntityWrapperPtr PlaneGCSSolver_AttributeBuilder::createAttribute(
     aResult->setExternal(true);
   return aResult;
 }
+
+bool PlaneGCSSolver_AttributeBuilder::updateAttribute(
+    AttributePtr theAttribute,
+    EntityWrapperPtr theEntity)
+{
+  bool isUpdated = false;
+  GCS::SET_pD aParamsToRemove;
+  // rebuild array if its size is changed
+  if (theEntity->type() == ENTITY_POINT_ARRAY) {
+    std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> aWrapper =
+        std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(theEntity);
+    std::shared_ptr<GeomDataAPI_Point2DArray> anAttribute =
+        std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(theAttribute);
+
+    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
+        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()) {
+        // remove middle points
+        std::vector<PointWrapperPtr>::iterator anIt = --aPointsArray.end();
+        GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(*anIt);
+        aParamsToRemove.insert(aParams.begin(), aParams.end());
+        aPointsArray.erase(anIt);
+      }
+
+      aWrapper->setArray(aPointsArray);
+    }
+  }
+  else if (theEntity->type() == ENTITY_SCALAR_ARRAY) {
+    std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> aWrapper =
+        std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(theEntity);
+    if (aWrapper->size() != PlaneGCSSolver_Tools::AttributeArray(theAttribute).size()) {
+      aParamsToRemove = PlaneGCSSolver_Tools::parameters(aWrapper);
+      std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> aNewArray =
+          std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(
+          createScalarArray(theAttribute, myStorage));
+      aWrapper->setArray(aNewArray->array());
+      isUpdated = true;
+    }
+  }
+
+  if (!aParamsToRemove.empty()) {
+    if (myStorage)
+      myStorage->removeParameters(aParamsToRemove);
+    else {
+      std::for_each(aParamsToRemove.begin(), aParamsToRemove.end(),
+                    [](double* theParam) { delete theParam; });
+    }
+  }
+
+  return isUpdated || theEntity->update(theAttribute);
+}