-// 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_Builder.h>
#include <PlaneGCSSolver_Solver.h>
+#include <PlaneGCSSolver_BooleanWrapper.h>
#include <PlaneGCSSolver_ConstraintWrapper.h>
-#include <PlaneGCSSolver_EntityWrapper.h>
+#include <PlaneGCSSolver_EdgeWrapper.h>
#include <PlaneGCSSolver_PointWrapper.h>
-#include <PlaneGCSSolver_ScalarWrapper.h>
-#include <PlaneGCSSolver_ParameterWrapper.h>
+#include <PlaneGCSSolver_PointArrayWrapper.h>
+#include <PlaneGCSSolver_ScalarArrayWrapper.h>
+#include <PlaneGCSSolver_Tools.h>
+
+#include <PlaneGCSSolver_AttributeBuilder.h>
+#include <PlaneGCSSolver_FeatureBuilder.h>
+#include <PlaneGCSSolver_EntityDestroyer.h>
-#include <GeomAPI_Edge.h>
#include <GeomAPI_Dir2d.h>
#include <GeomAPI_Pnt2d.h>
#include <GeomAPI_XY.h>
#include <GeomDataAPI_Point2D.h>
-#include <SketchPlugin_Arc.h>
-#include <SketchPlugin_ConstraintTangent.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>
-PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const GroupID& theGroup)
- : SketchSolver_Storage(theGroup),
- myEntityLastID(EID_SKETCH),
+static void constraintsToSolver(const ConstraintWrapperPtr& theConstraint,
+ const SolverPtr& theSolver)
+{
+ const std::list<GCSConstraintPtr>& aConstraints =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint)->constraints();
+ theSolver->addConstraint(theConstraint->id(), aConstraints);
+}
+
+
+PlaneGCSSolver_Storage::PlaneGCSSolver_Storage(const SolverPtr& theSolver)
+ : SketchSolver_Storage(theSolver),
myConstraintLastID(CID_UNKNOWN)
{
}
void PlaneGCSSolver_Storage::addConstraint(
- ConstraintPtr theConstraint,
- std::list<ConstraintWrapperPtr> theSolverConstraints)
+ ConstraintPtr theConstraint,
+ ConstraintWrapperPtr theSolverConstraint)
{
- SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraints);
-
- // update point-point coincidence
- if (!theSolverConstraints.empty() &&
- theSolverConstraints.front()->type() == CONSTRAINT_PT_PT_COINCIDENT) {
- std::list<ConstraintWrapperPtr>::iterator aCIt = theSolverConstraints.begin();
- for (; aCIt != theSolverConstraints.end(); ++aCIt)
- update(*aCIt);
- }
-}
+ SketchSolver_Storage::addConstraint(theConstraint, theSolverConstraint);
+ theSolverConstraint->setId(++myConstraintLastID);
+ constraintsToSolver(theSolverConstraint, mySketchSolver);
+}
-bool PlaneGCSSolver_Storage::update(ConstraintWrapperPtr theConstraint)
+void PlaneGCSSolver_Storage::addMovementConstraint(
+ const ConstraintWrapperPtr& theSolverConstraint)
{
- bool isUpdated = false;
- std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
- std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
-
- // point-Line distance should be positive
- if (aConstraint->type() == CONSTRAINT_PT_LINE_DISTANCE && aConstraint->value() < 0.0)
- aConstraint->setValue(-aConstraint->value());
-
- // make value of constraint unchangeable
- ParameterWrapperPtr aValue = aConstraint->valueParameter();
- if (aValue)
- isUpdated = update(aValue) || isUpdated;
-
- // update constrained entities
- std::list<EntityWrapperPtr> anEntities = theConstraint->entities();
- std::list<EntityWrapperPtr>::iterator anIt = anEntities.begin();
- for (; anIt != anEntities.end(); ++anIt)
- isUpdated = update(*anIt) || isUpdated;
-
- if (aConstraint->id() == CID_UNKNOWN) {
- const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
- // check middle-point constraint conflicts with point-on-line
- if (aConstraint->type() == CONSTRAINT_MIDDLE_POINT) {
- std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
- anIt = myConstraintMap.begin();
- for (; anIt != myConstraintMap.end(); ++anIt) {
- EntityWrapperPtr aPoint, aLine;
- ConstraintWrapperPtr aCurrentConstr = anIt->second.front();
- if (aCurrentConstr->type() != CONSTRAINT_PT_ON_LINE)
- continue;
- const std::list<EntityWrapperPtr>& aCurSubs = aCurrentConstr->entities();
- std::list<EntityWrapperPtr>::const_iterator aSIt1, aSIt2;
- for (aSIt1 = aSubs.begin(); aSIt1 != aSubs.end(); ++aSIt1) {
- if ((*aSIt1)->type() == ENTITY_POINT)
- aPoint = *aSIt1;
- else if((*aSIt1)->type() == ENTITY_LINE)
- aLine = *aSIt1;
- else
- continue;
- for (aSIt2 = aCurSubs.begin(); aSIt2 != aCurSubs.end(); ++aSIt2)
- if ((*aSIt1)->id() == (*aSIt2)->id())
- break;
- if (aSIt2 == aCurSubs.end())
- break;
- }
- // point-on-line found, change it to bisector
- if (aSIt1 == aSubs.end()) {
- std::list<GCSConstraintPtr> aConstrList = aConstraint->constraints();
- aConstrList.pop_front();
- aConstraint->setConstraints(aConstrList);
- break;
- }
- }
- }
+ // before adding movement constraint to solver, re-check its DOF
+ if (mySketchSolver->dof() == 0)
+ mySketchSolver->diagnose();
- // Change ID of constraints
- aConstraint->setId(++myConstraintLastID);
- }
+ theSolverConstraint->setId(CID_MOVEMENT);
+ constraintsToSolver(theSolverConstraint, mySketchSolver);
+}
- return isUpdated;
+
+EntityWrapperPtr PlaneGCSSolver_Storage::createFeature(
+ const FeaturePtr& theFeature,
+ PlaneGCSSolver_EntityBuilder* theBuilder)
+{
+ std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+ std::list<AttributePtr>::const_iterator anIt = anAttributes.begin();
+ for (; anIt != anAttributes.end(); ++anIt)
+ createAttribute(*anIt, theBuilder);
+
+ EntityWrapperPtr aResult = theBuilder->createFeature(theFeature);
+ if (aResult)
+ addEntity(theFeature, aResult);
+ return aResult;
}
-/// \brief Update coordinates of the point or scalar using its base attribute
-static bool updateValues(EntityWrapperPtr& theEntity)
+EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute(
+ const AttributePtr& theAttribute,
+ PlaneGCSSolver_EntityBuilder* theBuilder)
{
- bool isUpdated = false;
- AttributePtr anAttr = theEntity->baseAttribute();
- const std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
-
- double aCoord[2];
-
- std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
- std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr);
- if (aPoint2D) {
- aCoord[0] = aPoint2D->x();
- aCoord[1] = aPoint2D->y();
- } else {
- AttributeDoublePtr aScalar = std::dynamic_pointer_cast<ModelAPI_AttributeDouble>(anAttr);
- if (aScalar)
- aCoord[0] = aScalar->value();
- }
+ EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute);
+ if (aResult)
+ addEntity(theAttribute, aResult);
+ return aResult;
+}
- std::list<ParameterWrapperPtr>::const_iterator anIt = aParams.begin();
- for (int i = 0; anIt != aParams.end(); ++anIt, ++i)
- if (fabs((*anIt)->value() - aCoord[i]) > tolerance) {
- (*anIt)->setValue(aCoord[i]);
- isUpdated = true;
- }
- return isUpdated;
+static bool hasReference(std::shared_ptr<SketchPlugin_Feature> theFeature,
+ const std::string& theFeatureKind)
+{
+ 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 false;
}
-bool PlaneGCSSolver_Storage::update(EntityWrapperPtr theEntity)
+static bool isCopyFeature(std::shared_ptr<SketchPlugin_Feature> theFeature)
{
- if (theEntity->type() == ENTITY_SKETCH)
- return true; // sketch is not necessary for PlaneGCS, so it is always says true
+ 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
+ sendNotify = true;
+ else { // Feature is not exist, create it
+ 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 && !isProjReferred) &&
+ myFeatureMap.find(theFeature) == myFeatureMap.end())
+ return false;
+
+ // external feature processing
+ bool isExternal =
+ (aSketchFeature && (aSketchFeature->isExternal() || isCopy || isProjReferred));
+
+ PlaneGCSSolver_FeatureBuilder aBuilder(isExternal ? 0 : this);
+
+ // Reserve the feature in the map of features
+ // (do not want to add several copies of it while adding attributes)
+ aRelated = createFeature(theFeature, &aBuilder);
+ myFeatureMap[theFeature] = aRelated;
+ createAuxiliaryConstraints(aRelated);
+ isUpdated = true;
+ }
- if (theEntity->baseAttribute()) {
- isUpdated = updateValues(theEntity);
- if (isUpdated) {
- setNeedToResolve(true);
- if (theEntity->type() == ENTITY_POINT && theEntity->group() != myGroupID)
- updateCoincident(theEntity);
- }
+ std::list<AttributePtr> anAttributes = theFeature->data()->attributes(std::string());
+ std::list<AttributePtr>::iterator anAttrIt = anAttributes.begin();
+ for (; anAttrIt != anAttributes.end(); ++anAttrIt)
+ if (PlaneGCSSolver_Tools::isAttributeApplicable((*anAttrIt)->id(), theFeature->getKind()))
+ isUpdated = update(*anAttrIt) || isUpdated;
+
+ // 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;
}
- // update parameters
- std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
- std::list<ParameterWrapperPtr>::iterator aPIt = aParams.begin();
- for (; aPIt != aParams.end(); ++aPIt)
- isUpdated = update(*aPIt) || isUpdated;
+ // send notification to listeners due to at least one attribute is changed
+ if (sendNotify && isUpdated)
+ notify(theFeature);
- // update sub-entities
- std::list<EntityWrapperPtr> aSubEntities = theEntity->subEntities();
- std::list<EntityWrapperPtr>::iterator aSIt = aSubEntities.begin();
- for (; aSIt != aSubEntities.end(); ++aSIt)
- isUpdated = update(*aSIt) || isUpdated;
+ // update arc
+ if (aRelated)
+ PlaneGCSSolver_Tools::recalculateArcParameters(aRelated);
- // additional constraints for the arc processing
- if (theEntity->type() == ENTITY_ARC)
- processArc(theEntity);
-
- // Change entity's ID, if necessary
- if (theEntity->id() == EID_UNKNOWN) {
- if (theEntity->type() == ENTITY_POINT) {
- std::shared_ptr<PlaneGCSSolver_PointWrapper> aPoint =
- std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theEntity);
- if (!aPoint) {
- aPoint = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
- theEntity->subEntities().front());
- }
- aPoint->setId(++myEntityLastID);
- } else if (theEntity->type() == ENTITY_SCALAR) {
- std::shared_ptr<PlaneGCSSolver_ScalarWrapper> aScalar =
- std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(theEntity);
- aScalar->setId(++myEntityLastID);
- } else {
- std::shared_ptr<PlaneGCSSolver_EntityWrapper> aGCSEnt =
- std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theEntity);
- aGCSEnt->setId(++myEntityLastID);
- }
- }
return isUpdated;
}
-bool PlaneGCSSolver_Storage::update(ParameterWrapperPtr theParameter)
+bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce)
{
- std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam =
- std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(theParameter);
- if (aParam->isProcessed())
+ if (!theAttribute->isInitialized())
return false;
- if (theParameter->group() != myGroupID || theParameter->isParametric())
- myConst.push_back(aParam->parameter());
- else
- myParameters.push_back(aParam->parameter());
- aParam->setProcessed(true);
- return true;
-}
-
-bool PlaneGCSSolver_Storage::remove(ConstraintWrapperPtr theConstraint)
-{
- std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aConstraint =
- std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(theConstraint);
-
- bool isFullyRemoved = true;
- // remove point-point coincidence
- if (aConstraint->type() == CONSTRAINT_PT_PT_COINCIDENT)
- isFullyRemoved = removeCoincidence(theConstraint) && isFullyRemoved;
- // remove sub-entities
- const std::list<EntityWrapperPtr>& aSubs = aConstraint->entities();
- std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
- for (; aSIt != aSubs.end(); ++ aSIt)
- isFullyRemoved = remove(*aSIt) && isFullyRemoved;
-
- if (aConstraint->valueParameter())
- isFullyRemoved = remove(aConstraint->valueParameter()) && isFullyRemoved;
- if (!isFullyRemoved && aConstraint->baseConstraint() &&
- (!aConstraint->baseConstraint()->data() || !aConstraint->baseConstraint()->data()->isValid()))
- isFullyRemoved = true;
- setNeedToResolve(true);
- myRemovedConstraints.insert(myRemovedConstraints.end(),
- aConstraint->constraints().begin(), aConstraint->constraints().end());
-
- if (isFullyRemoved && theConstraint->id() == myConstraintLastID)
- --myConstraintLastID;
-
- return isFullyRemoved;
-}
-
-bool PlaneGCSSolver_Storage::remove(EntityWrapperPtr theEntity)
-{
- // do not remove entity, if it is used by constraints or other entities
- if ((theEntity->baseFeature() && isUsed(theEntity->baseFeature())) ||
- (theEntity->baseAttribute() && isUsed(theEntity->baseAttribute())))
- return false;
+ AttributePtr anAttribute = theAttribute;
+ AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(anAttribute);
+ if (aRefAttr) {
+ if (aRefAttr->isObject()) {
+ FeaturePtr aFeature;
+ /// TODO: Check resultToFeatureOrAttribute() precisely.
+ resultToFeatureOrAttribute(aRefAttr->object(), aFeature, anAttribute);
+ if (aFeature)
+ return update(aFeature, theForce);
+ } else
+ anAttribute = aRefAttr->attr();
+ }
- bool isFullyRemoved = SketchSolver_Storage::remove(theEntity);
- if (isFullyRemoved) {
- if (theEntity->type() == ENTITY_ARC) {
- // remove arc additional constraints
- std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::iterator
- aFound = myArcConstraintMap.find(theEntity);
- if (aFound != myArcConstraintMap.end()) {
- myRemovedConstraints.insert(myRemovedConstraints.end(),
- aFound->second.begin(), aFound->second.end());
- myArcConstraintMap.erase(aFound);
- }
- }
- if (theEntity->id() == myEntityLastID)
- --myEntityLastID;
+ 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.
+ if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end())
+ return update(aFeature, theForce); // theAttribute has been processed while adding feature
+ return aRelated.get() != 0;
}
- return isFullyRemoved;
-}
-bool PlaneGCSSolver_Storage::remove(ParameterWrapperPtr theParameter)
-{
- std::shared_ptr<PlaneGCSSolver_ParameterWrapper> aParam =
- std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(theParameter);
- if (aParam->isProcessed()) {
- double* aValPtr = aParam->parameter();
- GCS::VEC_pD::iterator anIt = myParameters.begin();
- for (; anIt != myParameters.end(); ++anIt)
- if (*anIt == aValPtr)
- break;
- if (anIt != myParameters.end()) {
- myParameters.erase(anIt);
- setNeedToResolve(true);
- aParam->setProcessed(false);
- }
- else {
- for (anIt = myConst.begin(); anIt != myConst.end(); ++anIt)
- if (*anIt == aValPtr)
- break;
- if (anIt != myConst.end()) {
- myConst.erase(anIt);
- setNeedToResolve(true);
- aParam->setProcessed(false);
- }
- }
+ PlaneGCSSolver_AttributeBuilder aBuilder(aRelated->isExternal() ? 0 : this);
+ bool isUpdated = aBuilder.updateAttribute(anAttribute, aRelated);
+ if (isUpdated) {
+ setNeedToResolve(true);
+ notify(aFeature);
}
- return true;
+ return isUpdated;
}
-
-void PlaneGCSSolver_Storage::addCoincidentPoints(
- EntityWrapperPtr theMaster, EntityWrapperPtr theSlave)
+void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity)
{
- if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT)
+ if (theEntity->isExternal())
return;
- std::shared_ptr<PlaneGCSSolver_PointWrapper> aMaster =
- std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theMaster);
- if (!aMaster)
- aMaster = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
- std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theMaster)->subEntities().front());
- std::shared_ptr<PlaneGCSSolver_PointWrapper> aSlave =
- std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(theSlave);
- if (!aSlave)
- aSlave = std::dynamic_pointer_cast<PlaneGCSSolver_PointWrapper>(
- std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theSlave)->subEntities().front());
-
- // Search available coincidence
- CoincidentPointsMap::iterator aMasterFound = myCoincidentPoints.find(aMaster);
- CoincidentPointsMap::iterator aSlaveFound = myCoincidentPoints.find(aSlave);
- if (aMasterFound == myCoincidentPoints.end() && aSlaveFound == myCoincidentPoints.end()) {
- // try to find master and slave points in the lists of slaves of already existent coincidences
- CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin();
- for (; anIt != myCoincidentPoints.end(); ++anIt) {
- if (anIt->second.find(aMaster) != anIt->second.end())
- aMasterFound = anIt;
- else if (anIt->second.find(aSlave) != anIt->second.end())
- aSlaveFound = anIt;
-
- if (aMasterFound != myCoincidentPoints.end() && aSlaveFound != myCoincidentPoints.end())
- break;
- }
- }
-
- if (aMasterFound == myCoincidentPoints.end()) {
- // create new group
- myCoincidentPoints[aMaster] = std::set<EntityWrapperPtr>();
- aMasterFound = myCoincidentPoints.find(aMaster);
- } else if (aMasterFound == aSlaveFound)
- return; // already coincident
-
- if (aSlaveFound != myCoincidentPoints.end()) {
- // A slave has been found, we need to attach all points coincident with it to the new master
- std::set<EntityWrapperPtr> aNewSlaves = aSlaveFound->second;
- aNewSlaves.insert(aSlaveFound->first);
- myCoincidentPoints.erase(aSlaveFound);
-
- std::set<EntityWrapperPtr>::const_iterator aSlIt = aNewSlaves.begin();
- for (; aSlIt != aNewSlaves.end(); ++aSlIt)
- addCoincidentPoints(aMaster, *aSlIt);
- } else {
- //std::list<ParameterWrapperPtr> aSlaveParams = aSlave->parameters();
- //aSlave->setParameters(aMaster->parameters());
-
- //// Remove slave's parameters
- //std::list<ParameterWrapperPtr>::iterator aParIt = aSlaveParams.begin();
- //for (; aParIt != aSlaveParams.end(); ++aParIt)
- // remove(*aParIt);
-
- aMasterFound->second.insert(aSlave);
- }
-}
-
+ removeAuxiliaryConstraints(theEntity);
-void PlaneGCSSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup)
-{
- theEntity->setGroup(theGroup);
- if (theGroup == myGroupID)
- makeVariable(theEntity);
- else {
- if (theEntity->type() == ENTITY_POINT)
- update(theEntity);
- makeConstant(theEntity);
- }
+ GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
+ mySketchSolver->removeParameters(aParameters);
+ theEntity->setExternal(true);
+ myNeedToResolve = true;
}
-void PlaneGCSSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup)
+void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity)
{
- // TODO
-}
+ if (!theEntity->isExternal())
+ return;
-void PlaneGCSSolver_Storage::verifyFixed()
-{
- // TODO
-}
+ GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity);
+ mySketchSolver->addParameters(aParameters);
+ theEntity->setExternal(false);
-void PlaneGCSSolver_Storage::processArc(const EntityWrapperPtr& theArc)
-{
- // no need to constraint a fixed arc
- if (theArc->group() == GID_OUTOFGROUP)
- return;
+ createAuxiliaryConstraints(theEntity);
- // Calculate additional parameters necessary for PlaneGCS
- const std::list<EntityWrapperPtr>& aSubs = theArc->subEntities();
- std::list<EntityWrapperPtr>::const_iterator aSubIt = aSubs.begin();
- while ((*aSubIt)->type() == ENTITY_POINT) // search scalar entities
- ++aSubIt;
- double* aStartAngle = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt++)->scalar();
- double* aEndAngle = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt++)->scalar();
- double* aRadius = std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(*aSubIt)->scalar();
-
- std::shared_ptr<SketchPlugin_Feature> anArcFeature =
- std::dynamic_pointer_cast<SketchPlugin_Feature>(theArc->baseFeature());
- std::shared_ptr<GeomDataAPI_Point2D> aCenterAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aStartAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- anArcFeature->attribute(SketchPlugin_Arc::START_ID()));
- std::shared_ptr<GeomDataAPI_Point2D> aEndAttr = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- anArcFeature->attribute(SketchPlugin_Arc::END_ID()));
- if (!aCenterAttr || !aStartAttr || !aEndAttr)
- return;
- std::shared_ptr<GeomAPI_Pnt2d> aCenterPnt = aCenterAttr->pnt();
- std::shared_ptr<GeomAPI_Pnt2d> aStartPnt = aStartAttr->pnt();
- std::shared_ptr<GeomAPI_Pnt2d> aEndPnt = aEndAttr->pnt();
+ myNeedToResolve = true;
+}
- *aRadius = aCenterPnt->distance(aStartPnt);
- if (!anArcFeature->lastResult())
- return;
- std::shared_ptr<GeomAPI_Edge> anArcEdge =
- std::dynamic_pointer_cast<GeomAPI_Edge>(anArcFeature->lastResult()->shape());
- if (!anArcEdge)
- return;
- anArcEdge->getRange(*aStartAngle, *aEndAngle);
- // do not constraint copied arc
- if (anArcFeature->isCopy())
- return;
- // No need to add constraints if they are already exist
- std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::const_iterator
- aFound = myArcConstraintMap.find(theArc);
- if (aFound != myArcConstraintMap.end())
- return;
+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());
- // Prepare additional constraints to produce the arc
- std::vector<GCSConstraintPtr> anArcConstraints;
- std::shared_ptr<PlaneGCSSolver_EntityWrapper> anArcEnt =
- std::dynamic_pointer_cast<PlaneGCSSolver_EntityWrapper>(theArc);
- std::shared_ptr<GCS::Arc> anArc = std::dynamic_pointer_cast<GCS::Arc>(anArcEnt->entity());
- // Distances from center till start and end points are equal to radius
+ // 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)));
- // Angles of start and end points should be equal to given angles
+ // 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)));
- myArcConstraintMap[theArc] = anArcConstraints;
-}
+ ConstraintWrapperPtr aWrapper(
+ new PlaneGCSSolver_ConstraintWrapper(anArcConstraints, CONSTRAINT_UNKNOWN));
+ aWrapper->setId(theConstraintID);
+ constraintsToSolver(aWrapper, theSolver);
+ theConstraints[theArc] = aWrapper;
+}
-void PlaneGCSSolver_Storage::makeConstant(const EntityWrapperPtr& theEntity)
+static void createEllipseConstraints(
+ const EntityWrapperPtr& theEllipse,
+ const SolverPtr& theSolver,
+ const ConstraintID theConstraintID,
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
{
- toggleEntity(theEntity, myParameters, myConst);
- if (theEntity->type() == ENTITY_POINT)
- updateCoincident(theEntity);
+ 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;
}
-void PlaneGCSSolver_Storage::makeVariable(const EntityWrapperPtr& theEntity)
+static void createEllipticArcConstraints(
+ const EntityWrapperPtr& theEllipticArc,
+ const SolverPtr& theSolver,
+ const ConstraintID theConstraintID,
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
{
- toggleEntity(theEntity, myConst, myParameters);
+ // 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 getParametersToMove(const EntityWrapperPtr& theEntity, std::set<double*>& theParamList)
+static void createBSplineConstraints(
+ const EntityWrapperPtr& theCurve,
+ const SolverPtr& theSolver,
+ const ConstraintID theConstraintID,
+ std::map<EntityWrapperPtr, ConstraintWrapperPtr>& theConstraints)
{
- const std::list<ParameterWrapperPtr> aParams = theEntity->parameters();
- std::list<ParameterWrapperPtr>::const_iterator aPIt = aParams.begin();
- for (; aPIt != aParams.end(); ++aPIt)
- theParamList.insert(
- std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(*aPIt)->parameter());
-
- const std::list<EntityWrapperPtr> aSubs = theEntity->subEntities();
- std::list<EntityWrapperPtr>::const_iterator aSIt = aSubs.begin();
-
- if (theEntity->type() == ENTITY_ARC) {
- // workaround for the arc processing, because the arc is fixed by a set of constraints,
- // which will conflict with all parameters fixed:
- // 1. take center
- getParametersToMove(*aSIt++, theParamList);
- // 2. take start point
- getParametersToMove(*aSIt++, theParamList);
- // 3. skip end point, radius and start angle, but take end angle parameter
- getParametersToMove(*(++aSIt), theParamList);
- } else {
- for (; aSIt != aSubs.end(); ++aSIt)
- getParametersToMove(*aSIt, theParamList);
- }
+ // 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::toggleEntity(
- const EntityWrapperPtr& theEntity, GCS::VEC_pD& theFrom, GCS::VEC_pD& theTo)
+void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity)
{
- std::set<double*> aParamsToMove;
- getParametersToMove(theEntity, aParamsToMove);
+ if (!theEntity || theEntity->isExternal())
+ return;
- GCS::VEC_pD::iterator anIt = theFrom.begin();
- while (anIt != theFrom.end()) {
- if (aParamsToMove.find(*anIt) == aParamsToMove.end()) {
- ++anIt;
- continue;
- }
+ 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);
+}
- theTo.push_back(*anIt);
- int aShift = int(anIt - theFrom.begin());
- theFrom.erase(anIt);
- anIt = theFrom.begin() + aShift;
+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);
}
}
-void PlaneGCSSolver_Storage::updateCoincident(const EntityWrapperPtr& thePoint)
+template <typename ARCTYPE>
+void adjustArcParametrization(ARCTYPE& theArc, bool theReversed)
{
- CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin();
- for (; anIt != myCoincidentPoints.end(); ++anIt) {
- if (anIt->first == thePoint || anIt->second.find(thePoint) != anIt->second.end()) {
- std::set<EntityWrapperPtr> aCoincident = anIt->second;
- aCoincident.insert(anIt->first);
-
- const std::list<ParameterWrapperPtr>& aBaseParams = thePoint->parameters();
- std::list<ParameterWrapperPtr> aParams;
- std::list<ParameterWrapperPtr>::const_iterator aBaseIt, anUpdIt;
-
- std::set<EntityWrapperPtr>::const_iterator aCoincIt = aCoincident.begin();
- for (; aCoincIt != aCoincident.end(); ++aCoincIt)
- if (*aCoincIt != thePoint && (*aCoincIt)->group() != GID_OUTOFGROUP) {
- aParams = (*aCoincIt)->parameters();
- aBaseIt = aBaseParams.begin();
- for (anUpdIt = aParams.begin(); anUpdIt != aParams.end(); ++anUpdIt, ++aBaseIt)
- (*anUpdIt)->setValue((*aBaseIt)->value());
- }
+ // 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;
+ }
+}
- break;
+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::isRedundant(
- GCSConstraintPtr theCheckedConstraint,
- ConstraintWrapperPtr theParentConstraint,
- std::list<std::set<double*> >& theCoincidentPoints) const
+bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint)
{
- if (theParentConstraint->type() == CONSTRAINT_SYMMETRIC) {
- if (theCheckedConstraint->getTypeId() == GCS::Perpendicular) {
- BuilderPtr aBuilder = PlaneGCSSolver_Builder::getInstance();
- // check the initial point is placed on the mirror line
- std::list<EntityWrapperPtr> aSubs = theParentConstraint->entities();
- std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(aSubs.front());
- std::shared_ptr<GeomAPI_Lin2d> aLine = aBuilder->line(aSubs.back());
- return aLine->distance(aPoint) < tolerance;
+ std::map<ConstraintPtr, ConstraintWrapperPtr>::iterator
+ aFound = myConstraintMap.find(theConstraint);
+ if (aFound != myConstraintMap.end()) {
+ 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);
+
+ if (anID != CID_MOVEMENT)
+ myNeedToResolve = true;
+
+ // notify subscibers
+ notify(theConstraint);
}
- else if (theParentConstraint->type() == CONSTRAINT_PT_PT_COINCIDENT) {
- // Verify that the coincidence between points is already added
- GCS::VEC_pD aParams = theCheckedConstraint->params();
-
- std::list<std::set<double*> >::iterator aCoincIt, aFound1, aFound2;
- aFound1 = aFound2 = theCoincidentPoints.end();
- for (aCoincIt = theCoincidentPoints.begin(); aCoincIt != theCoincidentPoints.end(); ++aCoincIt) {
- if (aFound1 == theCoincidentPoints.end() && aCoincIt->find(aParams[0]) != aCoincIt->end())
- aFound1 = aCoincIt;
- if (aFound2 == theCoincidentPoints.end() && aCoincIt->find(aParams[1]) != aCoincIt->end())
- aFound2 = aCoincIt;
- if (aFound1 != theCoincidentPoints.end() && aFound2 != theCoincidentPoints.end())
- break;
+ return true;
+}
+
+void PlaneGCSSolver_Storage::removeInvalidEntities()
+{
+ PlaneGCSSolver_EntityDestroyer aDestroyer;
+
+ // Remove invalid constraints
+ std::list<ConstraintPtr> anInvalidConstraints;
+ std::map<ConstraintPtr, ConstraintWrapperPtr>::const_iterator
+ aCIter = myConstraintMap.begin();
+ for (; aCIter != myConstraintMap.end(); ++aCIter)
+ if (!aCIter->first->data() || !aCIter->first->data()->isValid())
+ anInvalidConstraints.push_back(aCIter->first);
+ std::list<ConstraintPtr>::const_iterator anInvCIt = anInvalidConstraints.begin();
+ for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt)
+ removeConstraint(*anInvCIt);
+
+ // Remove invalid features
+ std::list<FeaturePtr> anInvalidFeatures;
+ std::map<FeaturePtr, EntityWrapperPtr>::const_iterator aFIter = myFeatureMap.begin();
+ for (; aFIter != myFeatureMap.end(); aFIter++)
+ if (!aFIter->first->data() || !aFIter->first->data()->isValid()) {
+ anInvalidFeatures.push_back(aFIter->first);
+ if (aFIter->second)
+ aDestroyer.remove(aFIter->second);
+
+ // remove invalid arc
+ removeAuxiliaryConstraints(aFIter->second);
}
- if (aCoincIt != theCoincidentPoints.end()) { // both point are found
- if (aFound1 == aFound2)
- return true;
- // merge two groups of coincidence
- aFound1->insert(aFound2->begin(), aFound2->end());
- theCoincidentPoints.erase(aFound2);
- } else {
- if (aFound1 != theCoincidentPoints.end())
- aFound1->insert(aParams[1]);
- else if (aFound2 != theCoincidentPoints.end())
- aFound2->insert(aParams[0]);
- else {
- std::set<double*> aNewCoincidence;
- aNewCoincidence.insert(aParams[0]);
- aNewCoincidence.insert(aParams[1]);
- theCoincidentPoints.push_back(aNewCoincidence);
- }
+ std::list<FeaturePtr>::const_iterator anInvFIt = anInvalidFeatures.begin();
+ for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt)
+ removeFeature(*anInvFIt);
+
+ // Remove invalid attributes
+ std::list<AttributePtr> anInvalidAttributes;
+ std::map<AttributePtr, EntityWrapperPtr>::const_iterator anAttrIt = myAttributeMap.begin();
+ for (; anAttrIt != myAttributeMap.end(); ++anAttrIt) {
+ FeaturePtr anOwner = ModelAPI_Feature::feature(anAttrIt->first->owner());
+ if (!anOwner || !anOwner->data() || !anOwner->data()->isValid()) {
+ anInvalidAttributes.push_back(anAttrIt->first);
+ aDestroyer.remove(anAttrIt->second);
}
}
+ std::list<AttributePtr>::const_iterator anInvAtIt = anInvalidAttributes.begin();
+ for (; anInvAtIt != anInvalidAttributes.end(); ++anInvAtIt)
+ removeAttribute(*anInvAtIt);
- return false;
+ // free memory occupied by parameters
+ removeParameters(aDestroyer.parametersToRemove());
+
+ /// TODO: Think on optimization of checking invalid features and attributes
}
-void PlaneGCSSolver_Storage::initializeSolver(SolverPtr theSolver)
+
+
+double* PlaneGCSSolver_Storage::createParameter()
{
- std::shared_ptr<PlaneGCSSolver_Solver> aSolver =
- std::dynamic_pointer_cast<PlaneGCSSolver_Solver>(theSolver);
- if (!aSolver)
- return;
- aSolver->clear();
-
- if (myExistArc)
- processArcs();
-
- // initialize constraints
- std::map<ConstraintPtr, std::list<ConstraintWrapperPtr> >::const_iterator
- aCIt = myConstraintMap.begin();
- GCS::SET_I aTangentIDs;
- std::list<std::set<double*> > aCoincidentPoints;
- for (; aCIt != myConstraintMap.end(); ++aCIt) {
- std::list<ConstraintWrapperPtr>::const_iterator aCWIt = aCIt->second.begin();
- for (; aCWIt != aCIt->second.end(); ++ aCWIt) {
- std::shared_ptr<PlaneGCSSolver_ConstraintWrapper> aGCS =
- std::dynamic_pointer_cast<PlaneGCSSolver_ConstraintWrapper>(*aCWIt);
- std::list<GCSConstraintPtr>::const_iterator anIt = aGCS->constraints().begin();
- for (; anIt != aGCS->constraints().end(); ++anIt)
- if (!isRedundant(*anIt, aGCS, aCoincidentPoints))
- aSolver->addConstraint(*anIt);
- }
- // store IDs of tangent constraints to avoid incorrect report of redundant constraints
- if (aCIt->first && aCIt->first->getKind() == SketchPlugin_ConstraintTangent::ID())
- for (aCWIt = aCIt->second.begin(); aCWIt != aCIt->second.end(); ++ aCWIt)
- aTangentIDs.insert((int)(*aCWIt)->id());
- }
- // additional constraints for arcs
- std::map<EntityWrapperPtr, std::vector<GCSConstraintPtr> >::const_iterator
- anArcIt = myArcConstraintMap.begin();
- for (; anArcIt != myArcConstraintMap.end(); ++anArcIt) {
- std::vector<GCSConstraintPtr>::const_iterator anIt = anArcIt->second.begin();
- for (; anIt != anArcIt->second.end(); ++anIt)
- aSolver->addConstraint(*anIt);
- }
- // removed waste constraints
- std::list<GCSConstraintPtr>::const_iterator aRemIt = myRemovedConstraints.begin();
- for (; aRemIt != myRemovedConstraints.end(); ++aRemIt)
- aSolver->removeConstraint(*aRemIt);
- myRemovedConstraints.clear();
- // set list of tangent constraints
- aSolver->setTangent(aTangentIDs);
- // initialize unknowns
- aSolver->setParameters(myParameters);
+ return mySketchSolver->createParameter();
+}
+
+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
+static bool isExternalAttribute(const AttributePtr& theAttribute)
+{
+ if (!theAttribute)
+ return false;
+ std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
+ std::dynamic_pointer_cast<SketchPlugin_Feature>(theAttribute->owner());
+ 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(bool theFixedOnly) const
+void PlaneGCSSolver_Storage::refresh() const
{
- //blockEvents(true);
+ const double aTol = 1000. * tolerance; // tolerance to prevent frequent updates
+
+ std::set<FeaturePtr> anUpdatedFeatures;
std::map<AttributePtr, EntityWrapperPtr>::const_iterator anIt = myAttributeMap.begin();
- std::list<ParameterWrapperPtr> aParams;
- std::list<ParameterWrapperPtr>::const_iterator aParIt;
for (; anIt != myAttributeMap.end(); ++anIt) {
- // the external feature always should keep the up to date values, so,
- // refresh from the solver is never needed
- bool isExternal = false;
- if (anIt->first.get()) {
- std::shared_ptr<SketchPlugin_Feature> aSketchFeature =
- std::dynamic_pointer_cast<SketchPlugin_Feature>(anIt->first->owner());
- if (aSketchFeature.get() && aSketchFeature->isExternal())
- isExternal = true;
- }
+ if (!anIt->first->isInitialized())
+ continue;
- // update parameter wrappers and obtain values of attributes
- aParams = anIt->second->parameters();
- double aCoords[3];
- bool isUpd[3] = {false};
- int i = 0;
- for (aParIt = aParams.begin(); i < 3 && aParIt != aParams.end(); ++aParIt, ++i) {
- if (!theFixedOnly || isExternal ||
- (*aParIt)->group() == GID_OUTOFGROUP || (*aParIt)->isParametric()) {
- aCoords[i] = (*aParIt)->value();
- isUpd[i] = true;
- }
- }
- if (!isUpd[0] && !isUpd[1] && !isUpd[2])
- continue; // nothing is updated
+ // the external feature always should keep the up to date values, so,
+ // refresh from the solver is never needed
+ if (isExternalAttribute(anIt->first))
+ continue;
std::shared_ptr<GeomDataAPI_Point2D> aPoint2D =
std::dynamic_pointer_cast<GeomDataAPI_Point2D>(anIt->first);
if (aPoint2D) {
- if ((isUpd[0] && fabs(aPoint2D->x() - aCoords[0]) > tolerance) ||
- (isUpd[1] && fabs(aPoint2D->y() - aCoords[1]) > tolerance) || isExternal) {
- if (!isUpd[0] || isExternal) aCoords[0] = aPoint2D->x();
- if (!isUpd[1] || isExternal) aCoords[1] = aPoint2D->y();
- aPoint2D->setValue(aCoords[0], aCoords[1]);
- // Find points coincident with this one (probably not in GID_OUTOFGROUP)
- CoincidentPointsMap::const_iterator aCoincIt = myCoincidentPoints.begin();
- for (; aCoincIt != myCoincidentPoints.end(); ++aCoincIt)
- if (aCoincIt->first == anIt->second ||
- aCoincIt->second.find(anIt->second) != aCoincIt->second.end())
- break;
- if (aCoincIt != myCoincidentPoints.end()) {
- aPoint2D = std::dynamic_pointer_cast<GeomDataAPI_Point2D>(
- aCoincIt->first->baseAttribute());
- if (aPoint2D)
- aPoint2D->setValue(aCoords[0], aCoords[1]);
- std::set<EntityWrapperPtr>::const_iterator aSlaveIt = aCoincIt->second.begin();
- for (; aSlaveIt != aCoincIt->second.end(); ++aSlaveIt) {
- aPoint2D = std::dynamic_pointer_cast<GeomDataAPI_Point2D>((*aSlaveIt)->baseAttribute());
- if (aPoint2D)
- aPoint2D->setValue(aCoords[0], aCoords[1]);
- }
+ std::shared_ptr<PlaneGCSSolver_PointWrapper> aPointWrapper =
+ 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) {
+ 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 && !isExternal) {
- if (isUpd[0] && fabs(aScalar->value() - aCoords[0]) > tolerance)
- aScalar->setValue(aCoords[0]);
+ if (aScalar) {
+ ScalarWrapperPtr aScalarWrapper =
+ std::dynamic_pointer_cast<PlaneGCSSolver_ScalarWrapper>(anIt->second);
+ 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;
}
}
- //blockEvents(false);
+ // notify listeners about features update
+ std::set<FeaturePtr>::const_iterator aFIt = anUpdatedFeatures.begin();
+ for (; aFIt != anUpdatedFeatures.end(); ++aFIt)
+ notify(*aFIt);
}
-EntityWrapperPtr PlaneGCSSolver_Storage::calculateMiddlePoint(
- EntityWrapperPtr theBase, double theCoeff)
+PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeometry() const
{
- std::shared_ptr<PlaneGCSSolver_Builder> aBuilder =
- std::dynamic_pointer_cast<PlaneGCSSolver_Builder>(PlaneGCSSolver_Builder::getInstance());
-
- std::shared_ptr<GeomAPI_XY> aMidPoint;
- if (theBase->type() == ENTITY_LINE) {
- std::shared_ptr<GeomAPI_Pnt2d> aPoints[2];
- const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
- std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
- for (int i = 0; i < 2; ++i, ++anIt)
- aPoints[i] = aBuilder->point(*anIt);
- aMidPoint = aPoints[0]->xy()->multiplied(1.0 - theCoeff)->added(
- aPoints[1]->xy()->multiplied(theCoeff));
- }
- else if (theBase->type() == ENTITY_ARC) {
- double theX, theY;
- double anArcPoint[3][2];
- const std::list<EntityWrapperPtr>& aSubs = theBase->subEntities();
- std::list<EntityWrapperPtr>::const_iterator anIt = aSubs.begin();
- for (int i = 0; i < 3; ++i, ++anIt) {
- std::shared_ptr<GeomAPI_Pnt2d> aPoint = aBuilder->point(*anIt);
- anArcPoint[i][0] = aPoint->x();
- anArcPoint[i][1] = aPoint->y();
- }
- // project last point of arc on the arc
- double x = anArcPoint[1][0] - anArcPoint[0][0];
- double y = anArcPoint[1][1] - anArcPoint[0][1];
- double aRad = sqrt(x*x + y*y);
- x = anArcPoint[2][0] - anArcPoint[0][0];
- y = anArcPoint[2][1] - anArcPoint[0][1];
- double aNorm = sqrt(x*x + y*y);
- if (aNorm >= tolerance) {
- anArcPoint[2][0] = x * aRad / aNorm;
- anArcPoint[2][1] = y * aRad / aNorm;
- }
- anArcPoint[1][0] -= anArcPoint[0][0];
- anArcPoint[1][1] -= anArcPoint[0][1];
- if (theCoeff < tolerance) {
- theX = anArcPoint[0][0] + anArcPoint[1][0];
- theY = anArcPoint[0][1] + anArcPoint[1][1];
- } else if (1 - theCoeff < tolerance) {
- theX = anArcPoint[0][0] + anArcPoint[2][0];
- theY = anArcPoint[0][1] + anArcPoint[2][1];
- } else {
- std::shared_ptr<GeomAPI_Dir2d> aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1]));
- std::shared_ptr<GeomAPI_Dir2d> aEndDir(new GeomAPI_Dir2d(anArcPoint[2][0], anArcPoint[2][1]));
- double anAngle = aStartDir->angle(aEndDir);
- if (anAngle < 0)
- anAngle += 2.0 * PI;
- anAngle *= theCoeff;
- double aCos = cos(anAngle);
- double aSin = sin(anAngle);
- theX = anArcPoint[0][0] + anArcPoint[1][0] * aCos - anArcPoint[1][1] * aSin;
- theY = anArcPoint[0][1] + anArcPoint[1][0] * aSin + anArcPoint[1][1] * aCos;
- }
- aMidPoint = std::shared_ptr<GeomAPI_XY>(new GeomAPI_XY(theX, theY));
+ 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;
+}
- if (!aMidPoint)
- return EntityWrapperPtr();
-
- std::list<ParameterWrapperPtr> aParameters;
- aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->x()));
- aParameters.push_back(aBuilder->createParameter(myGroupID, aMidPoint->y()));
- // Create entity (parameters are not filled)
- GCSPointPtr aPnt(new GCS::Point);
- aPnt->x = std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(aParameters.front())->parameter();
- aPnt->y = std::dynamic_pointer_cast<PlaneGCSSolver_ParameterWrapper>(aParameters.back())->parameter();
- EntityWrapperPtr aResult(new PlaneGCSSolver_PointWrapper(AttributePtr(), aPnt));
- aResult->setGroup(myGroupID);
- aResult->setParameters(aParameters);
+void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set<ObjectPtr>& theFeatures) const
+{
+ std::set<double*> aFreeParams;
+ mySketchSolver->getFreeParameters(aFreeParams);
+ if (aFreeParams.empty())
+ return;
- update(aResult);
- return aResult;
+ 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;
+ }
+ }
}