-// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
-
-// File: PlaneGCSSolver_Storage.cpp
-// Created: 14 Dec 2015
-// Author: Artem ZHIDKOV
+// 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
+// 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 <PlaneGCSSolver_Storage.h>
#include <PlaneGCSSolver_Solver.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
#include <PlaneGCSSolver_ConstraintWrapper.h>
#include <PlaneGCSSolver_EdgeWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
#include <PlaneGCSSolver_AttributeBuilder.h>
#include <PlaneGCSSolver_FeatureBuilder.h>
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_XY.h>
#include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
+#include <ModelAPI_AttributeDoubleArray.h>
#include <ModelAPI_AttributeRefAttr.h>
+#include <SketchPlugin_BSpline.h>
+#include <SketchPlugin_Ellipse.h>
#include <SketchPlugin_Projection.h>
#include <cmath>
{
const std::list<GCSConstraintPtr>& aConstraints =
std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint)->constraints();
- std::list<GCSConstraintPtr>::const_iterator anIt = aConstraints.begin();
- for (; anIt != aConstraints.end(); ++anIt)
- theSolver->addConstraint(*anIt, theConstraint->type());
+ theSolver->addConstraint(theConstraint->id(), aConstraints);
}
constraintsToSolver(theSolverConstraint, mySketchSolver);
}
-void PlaneGCSSolver_Storage::addTemporaryConstraint(
+void PlaneGCSSolver_Storage::addMovementConstraint(
const ConstraintWrapperPtr& theSolverConstraint)
{
- if (myConstraintMap.empty())
- return; // no need to process temporary constraints if there is no active constraint
+ // before adding movement constraint to solver, re-check its DOF
+ if (mySketchSolver->dof() == 0)
+ mySketchSolver->diagnose();
theSolverConstraint->setId(CID_MOVEMENT);
constraintsToSolver(theSolverConstraint, mySketchSolver);
return aResult;
}
-/// \brief Update value
-static bool updateValue(const double& theSource, double& theDest)
+static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
+ const std::string& theFeatureKind)
{
- static const double aTol = 1000. * tolerance;
- bool isUpdated = fabs(theSource - theDest) > aTol;
- if (isUpdated)
- theDest = theSource;
- return isUpdated;
-}
-
-/// \brief Update coordinates of the point or scalar using its base attribute
-static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity)
-{
- bool isUpdated = false;
-
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttribute);
- if (aPoint2D) {
- const GCSPointPtr& aGCSPoint =
- std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity)->point();
- isUpdated = updateValue(aPoint2D->x(), *(aGCSPoint->x)) || isUpdated;
- isUpdated = updateValue(aPoint2D->y(), *(aGCSPoint->y)) || isUpdated;
- } else {
- AttributeDoublePtr aScalar =
- std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theAttribute);
- if (aScalar) {
- ScalarWrapperPtr aWrapper =
- std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
- // There is possible angular value, which is converted between degrees and radians.
- // So, we use its value instead of using direct pointer to value.
- double aValue = aWrapper->value();
- isUpdated = updateValue(aScalar->value(), aValue);
- if (isUpdated)
- aWrapper->setValue(aValue);
- }
+ const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
+ for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
+ aRefIt != aRefs.end(); ++aRefIt) {
+ FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
+ if (anOwner && !anOwner->isMacro() && anOwner->getKind() == theFeatureKind)
+ return true;
}
-
- return isUpdated;
+ return false;
}
-static bool isCopyInMulti(std::shared_ptr<SketchPlugin_Feature> theFeature)
+static bool isCopyFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
{
- if (!theFeature)
- return false;
-
- bool aResult = theFeature->isCopy();
- if (aResult) {
- const std::set<AttributePtr>& aRefs = theFeature->data()->refsToMe();
- for (std::set<AttributePtr>::const_iterator aRefIt = aRefs.begin();
- aRefIt != aRefs.end() && aResult; ++aRefIt) {
- FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner());
- if (anOwner->getKind() == SketchPlugin_Projection::ID())
- aResult = false;
- }
- }
- return aResult;
+ return theFeature && theFeature->isCopy();
}
bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce)
{
+ bool sendNotify = false;
bool isUpdated = false;
+ std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
EntityWrapperPtr aRelated = entity(theFeature);
if (aRelated) // send signal to subscribers
- notify(theFeature);
+ sendNotify = true;
else { // Feature is not exist, create it
- std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
- std::dynamic_pointer_cast<SketchPlugin_Feature>(theFeature);
- bool isCopy = isCopyInMulti(aSketchFeature);
+ bool isCopy = isCopyFeature(aSketchFeature);
+ bool isProjReferred = hasReference(aSketchFeature, SketchPlugin_Projection::ID());
// the feature is a copy in "Multi" constraint and does not used in other constraints
- if (!theForce && isCopy && myFeatureMap.find(theFeature) == myFeatureMap.end())
+ if (!theForce && (isCopy && !isProjReferred) &&
+ myFeatureMap.find(theFeature) == myFeatureMap.end())
return false;
// external feature processing
- bool isExternal = (aSketchFeature && (aSketchFeature->isExternal() || isCopy));
+ bool isExternal =
+ (aSketchFeature && (aSketchFeature->isExternal() || isCopy || isProjReferred));
PlaneGCSSolver_FeatureBuilder aBuilder(isExternal ? 0 : this);
// (do not want to add several copies of it while adding attributes)
aRelated = createFeature(theFeature, &aBuilder);
myFeatureMap[theFeature] = aRelated;
-
- const std::list<GCSConstraintPtr>& aConstraints = aBuilder.constraints();
- if (!aConstraints.empty()) { // the feature is arc
- /// TODO: avoid this workaround
- ConstraintWrapperPtr aWrapper(
- new PlaneGCSSolver_ConstraintWrapper(aConstraints, CONSTRAINT_UNKNOWN));
- aWrapper->setId(++myConstraintLastID);
- constraintsToSolver(aWrapper, mySketchSolver);
-
- myArcConstraintMap[myFeatureMap[theFeature]] = aWrapper;
- }
+ createAuxiliaryConstraints(aRelated);
isUpdated = true;
}
std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
for (; anAttrIt != anAttributes.end(); ++anAttrIt)
- if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() ||
- (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId())
+ if (PlaneGCSSolver_Tools::isAttributeApplicable((*anAttrIt)->id(), theFeature->getKind()))
isUpdated = update(*anAttrIt) || isUpdated;
- // update arc
- if (aRelated && aRelated->type() == ENTITY_ARC) {
- /// TODO: this code should be shared with FeatureBuilder somehow
-
- std::shared_ptr<PlaneGCSSolver_EdgeWrapper> anEntity =
- std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aRelated);
- std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEntity->entity());
-
- static std::shared_ptr<GeomAPI_Dir2d> OX(new GeomAPI_Dir2d(1.0, 0.0));
- std::shared_ptr<GeomAPI_Pnt2d> aCenter(
- new GeomAPI_Pnt2d(*anArc->center.x, *anArc->center.y));
- std::shared_ptr<GeomAPI_Pnt2d> aStart(
- new GeomAPI_Pnt2d(*anArc->start.x, *anArc->start.y));
-
- *anArc->rad = aStart->distance(aCenter);
+ // check external attribute is changed
+ bool isExternal = aSketchFeature &&
+ (aSketchFeature->isExternal() || isCopyFeature(aSketchFeature));
+ if (aRelated && isExternal != aRelated->isExternal()) {
+ if (isExternal)
+ makeExternal(aRelated);
+ else
+ makeNonExternal(aRelated);
+ isUpdated = true;
+ }
- std::shared_ptr<GeomAPI_Dir2d> aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy())));
- *anArc->startAngle = OX->angle(aDir);
+ // send notification to listeners due to at least one attribute is changed
+ if (sendNotify && isUpdated)
+ notify(theFeature);
- aDir = std::shared_ptr<GeomAPI_Dir2d>(
- new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y()));
- *anArc->endAngle = OX->angle(aDir);
- }
+ // update arc
+ if (aRelated)
+ PlaneGCSSolver_Tools::recalculateArcParameters(aRelated);
return isUpdated;
}
}
EntityWrapperPtr aRelated = entity(anAttribute);
+ FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
if (!aRelated) { // Attribute does not exist, create it.
// First of all check if the parent feature exists. If not, add it.
- FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner());
if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
return update(aFeature, theForce); // theAttribute has been processed while adding feature
-
-//// PlaneGCSSolver_AttributeBuilder aBuilder(this);
-//// aRelated = createAttribute(anAttribute, &aBuilder);
return aRelated.get() != 0;
}
- bool isUpdated = updateValues(anAttribute, aRelated);
- if (isUpdated)
+ PlaneGCSSolver_AttributeBuilder aBuilder(aRelated->isExternal() ? 0 : this);
+ bool isUpdated = aBuilder.updateAttribute(anAttribute, aRelated);
+ if (isUpdated) {
setNeedToResolve(true);
+ notify(aFeature);
+ }
return isUpdated;
}
+void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
+{
+ if (theEntity->isExternal())
+ return;
+
+ removeAuxiliaryConstraints(theEntity);
+
+ GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
+ mySketchSolver->removeParameters(aParameters);
+ theEntity->setExternal(true);
+ myNeedToResolve = true;
+}
+
+void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
+{
+ if (!theEntity->isExternal())
+ return;
+
+ GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
+ mySketchSolver->addParameters(aParameters);
+ theEntity->setExternal(false);
+
+ createAuxiliaryConstraints(theEntity);
+
+ myNeedToResolve = true;
+}
+
+
+static void createArcConstraints(const EntityWrapperPtr& theArc,
+ const SolverPtr& theSolver,
+ const ConstraintID theConstraintID,
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+ EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theArc);
+ std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
+
+ // Additional constaints to fix arc's extra DoF (if the arc is not external):
+ std::list<GCSConstraintPtr> anArcConstraints;
+ // 1. distances from center till start and end points are equal to radius
+ anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+ anArc->center, anArc->start, anArc->rad)));
+ anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+ anArc->center, anArc->end, anArc->rad)));
+ // 2. angles of start and end points should be equal to the arc angles
+ anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
+ anArc->center, anArc->start, anArc->startAngle)));
+ anArcConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PAngle(
+ anArc->center, anArc->end, anArc->endAngle)));
+
+ ConstraintWrapperPtr aWrapper(
+ new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
+ aWrapper->setId(theConstraintID);
+ constraintsToSolver(aWrapper, theSolver);
+
+ theConstraints[theArc] = aWrapper;
+}
+
+static void createEllipseConstraints(
+ const EntityWrapperPtr& theEllipse,
+ const SolverPtr& theSolver,
+ const ConstraintID theConstraintID,
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+ EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipse);
+ std::shared_ptr<GCS::Ellipse> anEllipse =
+ std::dynamic_pointer_cast<GCS::Ellipse>(anEdge->entity());
+
+ // Additional constaints to fix ellipse's extra points
+ std::list<GCSConstraintPtr> anEllipseConstraints;
+
+ const std::map<std::string, EntityWrapperPtr>& anAttributes = theEllipse->additionalAttributes();
+ for (std::map<std::string, EntityWrapperPtr>::const_iterator anIt = anAttributes.begin();
+ anIt != anAttributes.end(); ++anIt) {
+ std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
+ if (!aPoint)
+ continue;
+
+ GCS::InternalAlignmentType anAlignmentX, anAlignmentY;
+ if (anIt->first == SketchPlugin_Ellipse::SECOND_FOCUS_ID())
+ anAlignmentX = GCS::EllipseFocus2X;
+ else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_START_ID())
+ anAlignmentX = GCS::EllipseNegativeMajorX;
+ else if (anIt->first == SketchPlugin_Ellipse::MAJOR_AXIS_END_ID())
+ anAlignmentX = GCS::EllipsePositiveMajorX;
+ else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_START_ID())
+ anAlignmentX = GCS::EllipseNegativeMinorX;
+ else if (anIt->first == SketchPlugin_Ellipse::MINOR_AXIS_END_ID())
+ anAlignmentX = GCS::EllipsePositiveMinorX;
+
+ anEllipseConstraints.push_back(GCSConstraintPtr(
+ new GCS::ConstraintInternalAlignmentPoint2Ellipse(
+ *anEllipse, *(aPoint->point()), anAlignmentX)));
+ anAlignmentY = (GCS::InternalAlignmentType)((int)anAlignmentX + 1);
+ anEllipseConstraints.push_back(GCSConstraintPtr(
+ new GCS::ConstraintInternalAlignmentPoint2Ellipse(
+ *anEllipse, *(aPoint->point()), anAlignmentY)));
+ }
+
+ // constraint to bind the major radius value
+ std::shared_ptr<PlaneGCSSolver_PointWrapper> aMajorAxisStart =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+ anAttributes.at(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID()));
+ ScalarWrapperPtr aMajorRadius =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(
+ anAttributes.at(SketchPlugin_Ellipse::MAJOR_RADIUS_ID()));
+ anEllipseConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintP2PDistance(
+ anEllipse->center, *(aMajorAxisStart->point()), aMajorRadius->scalar())));
+
+ ConstraintWrapperPtr aWrapper(
+ new PlaneGCSSolver_ConstraintWrapper(anEllipseConstraints, CONSTRAINT_UNKNOWN));
+ aWrapper->setId(theConstraintID);
+ if (theSolver)
+ constraintsToSolver(aWrapper, theSolver);
+
+ theConstraints[theEllipse] = aWrapper;
+}
+
+static void createEllipticArcConstraints(
+ const EntityWrapperPtr& theEllipticArc,
+ const SolverPtr& theSolver,
+ const ConstraintID theConstraintID,
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+ // create base constraints for the ellipse without adding them to solver
+ createEllipseConstraints(theEllipticArc, SolverPtr(), theConstraintID, theConstraints);
+
+ ConstraintWrapperPtr& aConstraint = theConstraints[theEllipticArc];
+ std::list<GCSConstraintPtr> anEllArcConstraints = aConstraint->constraints();
+
+ // constrain extremities of the elliptic arc
+ EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(theEllipticArc);
+ std::shared_ptr<GCS::ArcOfEllipse> anArc =
+ std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+
+ anEllArcConstraints.push_back(GCSConstraintPtr(
+ new GCS::ConstraintCurveValue(anArc->start, anArc->start.x, *anArc, anArc->startAngle)));
+ anEllArcConstraints.push_back(GCSConstraintPtr(
+ new GCS::ConstraintCurveValue(anArc->start, anArc->start.y, *anArc, anArc->startAngle)));
+ anEllArcConstraints.push_back(GCSConstraintPtr(
+ new GCS::ConstraintCurveValue(anArc->end, anArc->end.x, *anArc, anArc->endAngle)));
+ anEllArcConstraints.push_back(GCSConstraintPtr(
+ new GCS::ConstraintCurveValue(anArc->end, anArc->end.y, *anArc, anArc->endAngle)));
+
+ aConstraint->setConstraints(anEllArcConstraints);
+ constraintsToSolver(aConstraint, theSolver);
+}
+
+static void createBSplineConstraints(
+ const EntityWrapperPtr& theCurve,
+ const SolverPtr& theSolver,
+ const ConstraintID theConstraintID,
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
+{
+ // set start and end point of B-spline equal to first and last pole correspondingly
+ 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;
+
+ const std::map<std::string, EntityWrapperPtr>& anAdditional = anEdge->additionalAttributes();
+ PointWrapperPtr aStartPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+ anAdditional.at(SketchPlugin_BSpline::START_ID()));
+
+ const GCS::Point& sp = *aStartPoint->point();
+ const GCS::Point& p0 = aBSpline->poles.front();
+ aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.x, sp.x)));
+ aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(p0.y, sp.y)));
+
+ PointWrapperPtr aEndPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
+ anAdditional.at(SketchPlugin_BSpline::END_ID()));
+
+ const GCS::Point& ep = *aEndPoint->point();
+ const GCS::Point& pN = aBSpline->poles.back();
+ aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.x, ep.x)));
+ aBSplineConstraints.push_back(GCSConstraintPtr(new GCS::ConstraintEqual(pN.y, ep.y)));
+
+ ConstraintWrapperPtr aWrapper(
+ new PlaneGCSSolver_ConstraintWrapper(aBSplineConstraints, CONSTRAINT_UNKNOWN));
+ aWrapper->setId(theConstraintID);
+ if (theSolver)
+ constraintsToSolver(aWrapper, theSolver);
+
+ theConstraints[theCurve] = aWrapper;
+}
+
+void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
+{
+ if (!theEntity || theEntity->isExternal())
+ return;
+
+ if (theEntity->type() == ENTITY_ARC)
+ createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
+ else if (theEntity->type() == ENTITY_ELLIPSE)
+ createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
+ else if (theEntity->type() == ENTITY_ELLIPTIC_ARC) {
+ createEllipticArcConstraints(theEntity, mySketchSolver,
+ ++myConstraintLastID, myAuxConstraintMap);
+ }
+ else if (theEntity->type() == ENTITY_BSPLINE)
+ createBSplineConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap);
+}
+
+void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
+{
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
+ aFound = myAuxConstraintMap.find(theEntity);
+ if (aFound != myAuxConstraintMap.end()) {
+ mySketchSolver->removeConstraint(aFound->second->id());
+ myAuxConstraintMap.erase(aFound);
+ }
+}
+
+template <typename ARCTYPE>
+void adjustArcParametrization(ARCTYPE& theArc, bool theReversed)
+{
+ // tune start angle of the arc to be in [0, 2PI]
+ while (*theArc.startAngle < -PI)
+ *theArc.startAngle += 2.0 * PI;
+ while (*theArc.startAngle >= PI)
+ *theArc.startAngle -= 2.0 * PI;
+ // adjust end angle of the arc
+ if (theReversed) {
+ while (*theArc.endAngle > *theArc.startAngle)
+ *theArc.endAngle -= 2.0 * PI;
+ while (*theArc.endAngle + 2 * PI < *theArc.startAngle)
+ *theArc.endAngle += 2.0 * PI;
+ }
+ else {
+ while (*theArc.endAngle < *theArc.startAngle)
+ *theArc.endAngle += 2.0 * PI;
+ while (*theArc.endAngle > *theArc.startAngle + 2 * PI)
+ *theArc.endAngle -= 2.0 * PI;
+ }
+}
+
+void PlaneGCSSolver_Storage::adjustParametrizationOfArcs()
+{
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator anIt = myAuxConstraintMap.begin();
+ for (; anIt != myAuxConstraintMap.end(); ++anIt) {
+ EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(anIt->first);
+ std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anEdge->entity());
+ if (anArc)
+ adjustArcParametrization(*anArc, anEdge->isReversed());
+ else {
+ std::shared_ptr<GCS::ArcOfEllipse> aEllArc =
+ std::dynamic_pointer_cast<GCS::ArcOfEllipse>(anEdge->entity());
+ if (aEllArc)
+ adjustArcParametrization(*aEllArc, anEdge->isReversed());
+ }
+ }
+
+ // update parameters of Middle point constraint for point on arc
+ std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator aCIt = myConstraintMap.begin();
+ for (; aCIt != myConstraintMap.end(); ++aCIt)
+ if (aCIt->second->type() == CONSTRAINT_MIDDLE_POINT) {
+ notify(aCIt->first);
+ }
+}
bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator
aFound = myConstraintMap.find(theConstraint);
if (aFound != myConstraintMap.end()) {
- ConstraintID anID = aFound->second->id();
+ ConstraintWrapperPtr aCW = aFound->second;
+ ConstraintID anID = aCW->id();
+
// Remove solver's constraints
mySketchSolver->removeConstraint(anID);
+
+ // Remove value if exists
+ const ScalarWrapperPtr& aValue = aCW->valueParameter();
+ if (aValue) {
+ GCS::SET_pD aParToRemove;
+ aParToRemove.insert(aValue->scalar());
+ removeParameters(aParToRemove);
+ }
+
// Remove constraint
myConstraintMap.erase(aFound);
for (; aFIter != myFeatureMap.end(); aFIter++)
if (!aFIter->first->data() || !aFIter->first->data()->isValid()) {
anInvalidFeatures.push_back(aFIter->first);
- aDestroyer.remove(aFIter->second);
+ if (aFIter->second)
+ aDestroyer.remove(aFIter->second);
// remove invalid arc
- std::map<EntityWrapperPtr, ConstraintWrapperPtr>::iterator
- aFound = myArcConstraintMap.find(aFIter->second);
- if (aFound != myArcConstraintMap.end()) {
- mySketchSolver->removeConstraint(aFound->second->id());
- myArcConstraintMap.erase(aFound);
- }
+ removeAuxiliaryConstraints(aFIter->second);
}
std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams)
{
mySketchSolver->removeParameters(theParams);
+ //for (GCS::SET_pD::iterator it = theParams.begin(); it != theParams.end(); ++it)
+ // delete *it;
}
// indicates attribute containing in the external feature
-bool isExternalAttribute(const AttributePtr& theAttribute)
+static bool isExternalAttribute(const AttributePtr& theAttribute)
{
if (!theAttribute)
return false;
return aSketchFeature.get() && aSketchFeature->isExternal();
}
+static void addOwnerToSet(const AttributePtr& theAttribute, std::set<FeaturePtr>& theFeatures)
+{
+ FeaturePtr anOwner = ModelAPI_Feature::feature(theAttribute->owner());
+ if (anOwner)
+ theFeatures.insert(anOwner);
+}
+
void PlaneGCSSolver_Storage::refresh() const
{
const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
+ std::set<FeaturePtr> anUpdatedFeatures;
+
std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
for (; anIt != myAttributeMap.end(); ++anIt) {
+ if (!anIt->first->isInitialized())
+ continue;
+
// the external feature always should keep the up to date values, so,
// refresh from the solver is never needed
if (isExternalAttribute(anIt->first))
std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(anIt->second);
GCSPointPtr aGCSPoint = aPointWrapper->point();
if (fabs(aPoint2D->x() - (*aGCSPoint->x)) > aTol ||
- fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol)
+ fabs(aPoint2D->y() - (*aGCSPoint->y)) > aTol) {
aPoint2D->setValue(*aGCSPoint->x, *aGCSPoint->y);
+ addOwnerToSet(anIt->first, anUpdatedFeatures);
+ }
+ continue;
+ }
+ std::shared_ptr<GeomDataAPI_Point2DArray> aPointArray =
+ std::dynamic_pointer_cast<GeomDataAPI_Point2DArray>(anIt->first);
+ if (aPointArray) {
+ std::shared_ptr<PlaneGCSSolver_PointArrayWrapper> anArrayWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_PointArrayWrapper>(anIt->second);
+ int aSize = aPointArray->size();
+ for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+ GeomPnt2dPtr anOriginal = aPointArray->pnt(anIndex);
+ GCSPointPtr aGCSPoint = anArrayWrapper->value(anIndex)->point();
+ if (fabs(anOriginal->x() - (*aGCSPoint->x)) > aTol ||
+ fabs(anOriginal->y() - (*aGCSPoint->y)) > aTol) {
+ aPointArray->setPnt(anIndex, *aGCSPoint->x, *aGCSPoint->y);
+ addOwnerToSet(anIt->first, anUpdatedFeatures);
+ }
+ }
continue;
}
AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anIt->first);
if (aScalar) {
ScalarWrapperPtr aScalarWrapper =
std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
- if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol)
+ if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) {
aScalar->setValue(aScalarWrapper->value());
+ addOwnerToSet(anIt->first, anUpdatedFeatures);
+ }
continue;
}
+ AttributeDoubleArrayPtr aRealArray =
+ std::dynamic_pointer_cast<ModelAPI_AttributeDoubleArray>(anIt->first);
+ if (aRealArray) {
+ std::shared_ptr<PlaneGCSSolver_ScalarArrayWrapper> anArrayWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarArrayWrapper>(anIt->second);
+ int aSize = aRealArray->size();
+ for (int anIndex = 0; anIndex < aSize; ++anIndex) {
+ if (fabs(aRealArray->value(anIndex) - *anArrayWrapper->array()[anIndex]) > aTol) {
+ aRealArray->setValue(anIndex, *anArrayWrapper->array()[anIndex]);
+ addOwnerToSet(anIt->first, anUpdatedFeatures);
+ }
+ }
+ continue;
+ }
+ }
+
+ // notify listeners about features update
+ std::set<FeaturePtr>::const_iterator aFIt = anUpdatedFeatures.begin();
+ for (; aFIt != anUpdatedFeatures.end(); ++aFIt)
+ notify(*aFIt);
+}
+
+PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeometry() const
+{
+ std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
+ for (; aFIt != myFeatureMap.end(); ++aFIt) {
+ EdgeWrapperPtr anEdge = std::dynamic_pointer_cast<PlaneGCSSolver_EdgeWrapper>(aFIt->second);
+ if (anEdge && anEdge->isDegenerated())
+ return PlaneGCSSolver_Solver::STATUS_DEGENERATED;
+ }
+ return PlaneGCSSolver_Solver::STATUS_OK;
+}
+
+
+void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set<ObjectPtr>& theFeatures) const
+{
+ std::set<double*> aFreeParams;
+ mySketchSolver->getFreeParameters(aFreeParams);
+ if (aFreeParams.empty())
+ return;
+
+ for (std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIt = myFeatureMap.begin();
+ aFIt != myFeatureMap.end(); ++aFIt) {
+ if (!aFIt->second)
+ continue;
+ GCS::SET_pD aParams = PlaneGCSSolver_Tools::parameters(aFIt->second);
+ for (GCS::SET_pD::iterator aPIt = aParams.begin(); aPIt != aParams.end(); ++aPIt)
+ if (aFreeParams.find(*aPIt) != aFreeParams.end()) {
+ theFeatures.insert(aFIt->first);
+ break;
+ }
}
}