-// Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+// Copyright (C) 2014-2023 CEA, EDF
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
#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 <PlaneGCSSolver_Tools.h>
+#include <GeomAPI_Pnt2d.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
#include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeDoubleArray.h>
+#include <ModelAPI_AttributeInteger.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_BSplinePeriodic.h>
#include <SketchPlugin_ConstraintAngle.h>
#include <SketchPlugin_MultiRotation.h>
static EntityWrapperPtr createScalar(const AttributePtr& theAttribute,
PlaneGCSSolver_Storage* theStorage)
{
- AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
- if (!aScalar)
- return EntityWrapperPtr();
+ double aValue = 0.0;
+ AttributeDoublePtr aDouble = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
+ if (aDouble)
+ aValue = aDouble->isInitialized() ? aDouble->value() : 0.0;
+ else {
+ AttributeIntegerPtr anInt = std::dynamic_pointer_cast<ModelAPI_AttributeInteger>(theAttribute);
+ if (anInt)
+ aValue = anInt->isInitialized() ? anInt->value() : 0.0;
+ else
+ return EntityWrapperPtr();
+ }
ScalarWrapperPtr aWrapper;
// following attributes should be converted from degrees to radians
(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() ||
+ 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
aWrapper = ScalarWrapperPtr(new PlaneGCSSolver_ScalarWrapper(createParameter(theStorage)));
- if (aScalar->isInitialized())
- aWrapper->setValue(aScalar->value());
+ aWrapper->setValue(aValue);
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)
+{
+ PlaneGCSSolver_Tools::AttributeArray anArray(theAttribute);
+
+ if (!anArray.isInitialized())
+ return EntityWrapperPtr();
+
+ 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 (nonSolverAttribute<SketchPlugin_BSpline>(anOwner, theAttribute->id()) ||
+ nonSolverAttribute<SketchPlugin_BSplinePeriodic>(anOwner, theAttribute->id()))
+ aStorage = 0;
+
+ int aSize = anArray.size();
+ GCS::VEC_pD aParameters;
+ aParameters.reserve(aSize);
+ for (int index = 0; index < aSize; ++index) {
+ double* aParam = createParameter(aStorage);
+ *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)
{
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);
+}
+
+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();
- return EntityWrapperPtr(new PlaneGCSSolver_PointWrapper(aNewPoint));
+ 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(
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;
}
+
+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);
+
+ std::vector<PointWrapperPtr> aPointsArray = aWrapper->array();
+ std::vector<PointWrapperPtr>::iterator aPos = aPointsArray.begin();
+ if (aWrapper->size() != anAttribute->size()) {
+ 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 {
+ // update coordinates of points
+ for (int anIndex = 0; aPos != aPointsArray.end(); ++aPos, ++anIndex) {
+ const GCSPointPtr& aGCSPoint = (*aPos)->point();
+ GeomPnt2dPtr aCoord = anAttribute->pnt(anIndex);
+ *aGCSPoint->x = aCoord->x();
+ *aGCSPoint->y = aCoord->y();
+ }
+ }
+ }
+ 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);
+}