X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FPlaneGCSSolver%2FPlaneGCSSolver_Storage.cpp;h=878f232ff2e707366d1ddffac947fa325b5a2f32;hb=745c72679f6346375d5e886b25cc3865f3c4daae;hp=37086e22f611bf895b92ac3723742635ed96c59f;hpb=8a62402d4f55c542df46f57562996171e4b29ea7;p=modules%2Fshaper.git diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp index 37086e22f..878f232ff 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -1,662 +1,587 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: PlaneGCSSolver_Storage.cpp -// Created: 14 Dec 2015 -// Author: Artem ZHIDKOV +// Copyright (C) 2014-2021 CEA/DEN, EDF R&D +// +// 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 -#include #include +#include #include -#include +#include #include -#include -#include +#include +#include +#include + +#include +#include +#include -#include #include #include #include #include -#include -#include +#include +#include +#include +#include +#include +#include #include -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& aConstraints = + std::dynamic_pointer_cast(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 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::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 aConstraint = - std::dynamic_pointer_cast(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 anEntities = theConstraint->entities(); - std::list::iterator anIt = anEntities.begin(); - for (; anIt != anEntities.end(); ++anIt) - isUpdated = update(*anIt) || isUpdated; - - if (aConstraint->id() == CID_UNKNOWN) { - const std::list& aSubs = aConstraint->entities(); - // check middle-point constraint conflicts with point-on-line - if (aConstraint->type() == CONSTRAINT_MIDDLE_POINT) { - std::map >::const_iterator - anIt = myConstraintMap.begin(); - for (; anIt != myConstraintMap.end(); ++anIt) { - EntityWrapperPtr aPoint, aLine; - if (anIt->second.empty()) - continue; - ConstraintWrapperPtr aCurrentConstr = anIt->second.front(); - if (aCurrentConstr->type() != CONSTRAINT_PT_ON_LINE) - continue; - const std::list& aCurSubs = aCurrentConstr->entities(); - std::list::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 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 anAttributes = theFeature->data()->attributes(std::string()); + std::list::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) { - const double aTol = 1000. * tolerance; - bool isUpdated = false; - AttributePtr anAttr = theEntity->baseAttribute(); - const std::list aParams = theEntity->parameters(); - - double aCoord[2]; - - std::shared_ptr aPoint2D = - std::dynamic_pointer_cast(anAttr); - if (aPoint2D) { - aCoord[0] = aPoint2D->x(); - aCoord[1] = aPoint2D->y(); - } else { - AttributeDoublePtr aScalar = std::dynamic_pointer_cast(anAttr); - if (aScalar) - aCoord[0] = aScalar->value(); - } + EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute); + if (aResult) + addEntity(theAttribute, aResult); + return aResult; +} - std::list::const_iterator anIt = aParams.begin(); - for (int i = 0; anIt != aParams.end(); ++anIt, ++i) - if (fabs((*anIt)->value() - aCoord[i]) > aTol) { - (*anIt)->setValue(aCoord[i]); - isUpdated = true; - } - return isUpdated; +static bool hasReference(std::shared_ptr theFeature, + const std::string& theFeatureKind) +{ + const std::set& aRefs = theFeature->data()->refsToMe(); + for (std::set::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 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 aSketchFeature = + std::dynamic_pointer_cast(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 anAttributes = theFeature->data()->attributes(std::string()); + std::list::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 aParams = theEntity->parameters(); - std::list::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 aSubEntities = theEntity->subEntities(); - std::list::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 aPoint = - std::dynamic_pointer_cast(theEntity); - if (!aPoint) { - aPoint = std::dynamic_pointer_cast( - theEntity->subEntities().front()); - } - aPoint->setId(++myEntityLastID); - } else if (theEntity->type() == ENTITY_SCALAR) { - std::shared_ptr aScalar = - std::dynamic_pointer_cast(theEntity); - aScalar->setId(++myEntityLastID); - } else { - std::shared_ptr aGCSEnt = - std::dynamic_pointer_cast(theEntity); - aGCSEnt->setId(++myEntityLastID); - } - } return isUpdated; } -bool PlaneGCSSolver_Storage::update(ParameterWrapperPtr theParameter) +bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce) { - std::shared_ptr aParam = - std::dynamic_pointer_cast(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 aConstraint = - std::dynamic_pointer_cast(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& aSubs = aConstraint->entities(); - std::list::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; -} + AttributePtr anAttribute = theAttribute; + AttributeRefAttrPtr aRefAttr = std::dynamic_pointer_cast(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 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; + 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; + } - bool isFullyRemoved = SketchSolver_Storage::remove(theEntity); - if (isFullyRemoved) { - if (theEntity->type() == ENTITY_ARC) { - // remove arc additional constraints - std::map >::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; + PlaneGCSSolver_AttributeBuilder aBuilder(aRelated->isExternal() ? 0 : this); + bool isUpdated = aBuilder.updateAttribute(anAttribute, aRelated); + if (isUpdated) { + setNeedToResolve(true); + notify(aFeature); } - return isFullyRemoved; + return isUpdated; } -bool PlaneGCSSolver_Storage::remove(ParameterWrapperPtr theParameter) +void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity) { - std::shared_ptr aParam = - std::dynamic_pointer_cast(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); - } - } - } - return true; -} + if (theEntity->isExternal()) + return; + removeAuxiliaryConstraints(theEntity); -void PlaneGCSSolver_Storage::addCoincidentPoints( - EntityWrapperPtr theMaster, EntityWrapperPtr theSlave) + GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity); + mySketchSolver->removeParameters(aParameters); + theEntity->setExternal(true); + myNeedToResolve = true; +} + +void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity) { - if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT) + if (!theEntity->isExternal()) return; - std::shared_ptr aMaster = - std::dynamic_pointer_cast(theMaster); - if (!aMaster) - aMaster = std::dynamic_pointer_cast( - std::dynamic_pointer_cast(theMaster)->subEntities().front()); - std::shared_ptr aSlave = - std::dynamic_pointer_cast(theSlave); - if (!aSlave) - aSlave = std::dynamic_pointer_cast( - std::dynamic_pointer_cast(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; - } - } + GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity); + mySketchSolver->addParameters(aParameters); + theEntity->setExternal(false); - if (aMasterFound == myCoincidentPoints.end()) { - // create new group - myCoincidentPoints[aMaster] = std::set(); - 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 aNewSlaves = aSlaveFound->second; - aNewSlaves.insert(aSlaveFound->first); - myCoincidentPoints.erase(aSlaveFound); - - std::set::const_iterator aSlIt = aNewSlaves.begin(); - for (; aSlIt != aNewSlaves.end(); ++aSlIt) - addCoincidentPoints(aMaster, *aSlIt); - } else { - //std::list aSlaveParams = aSlave->parameters(); - //aSlave->setParameters(aMaster->parameters()); - - //// Remove slave's parameters - //std::list::iterator aParIt = aSlaveParams.begin(); - //for (; aParIt != aSlaveParams.end(); ++aParIt) - // remove(*aParIt); - - aMasterFound->second.insert(aSlave); - } + createAuxiliaryConstraints(theEntity); + + myNeedToResolve = true; } -void PlaneGCSSolver_Storage::changeGroup(EntityWrapperPtr theEntity, const GroupID& theGroup) +static void createArcConstraints(const EntityWrapperPtr& theArc, + const SolverPtr& theSolver, + const ConstraintID theConstraintID, + std::map& theConstraints) { - theEntity->setGroup(theGroup); - if (theGroup == myGroupID) - makeVariable(theEntity); - else { - if (theEntity->type() == ENTITY_POINT) - update(theEntity); - makeConstant(theEntity); - } + EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(theArc); + std::shared_ptr anArc = std::dynamic_pointer_cast(anEdge->entity()); + + // Additional constaints to fix arc's extra DoF (if the arc is not external): + std::list 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; } -void PlaneGCSSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup) +static void createEllipseConstraints( + const EntityWrapperPtr& theEllipse, + const SolverPtr& theSolver, + const ConstraintID theConstraintID, + std::map& theConstraints) { - // TODO -} + EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(theEllipse); + std::shared_ptr anEllipse = + std::dynamic_pointer_cast(anEdge->entity()); + + // Additional constaints to fix ellipse's extra points + std::list anEllipseConstraints; + + const std::map& anAttributes = theEllipse->additionalAttributes(); + for (std::map::const_iterator anIt = anAttributes.begin(); + anIt != anAttributes.end(); ++anIt) { + std::shared_ptr aPoint = + std::dynamic_pointer_cast(anIt->second); + if (!aPoint) + continue; -void PlaneGCSSolver_Storage::verifyFixed() -{ - // TODO + 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 aMajorAxisStart = + std::dynamic_pointer_cast( + anAttributes.at(SketchPlugin_Ellipse::MAJOR_AXIS_START_ID())); + ScalarWrapperPtr aMajorRadius = + std::dynamic_pointer_cast( + 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::processArc(const EntityWrapperPtr& theArc) +static void createEllipticArcConstraints( + const EntityWrapperPtr& theEllipticArc, + const SolverPtr& theSolver, + const ConstraintID theConstraintID, + std::map& theConstraints) { - // Calculate additional parameters necessary for PlaneGCS - const std::list& aSubs = theArc->subEntities(); - std::list::const_iterator aSubIt = aSubs.begin(); - bool isFixed[3] = {false, false, false}; - for (int i = 0; (*aSubIt)->type() == ENTITY_POINT; ++i) { // search scalar entities - isFixed[i] = (*aSubIt)->group() == GID_OUTOFGROUP; - ++aSubIt; - } - double* aStartAngle = - std::dynamic_pointer_cast(*aSubIt++)->scalar(); - double* aEndAngle = - std::dynamic_pointer_cast(*aSubIt++)->scalar(); - double* aRadius = std::dynamic_pointer_cast(*aSubIt)->scalar(); - - std::shared_ptr anArcFeature = - std::dynamic_pointer_cast(theArc->baseFeature()); - std::shared_ptr aCenterAttr = std::dynamic_pointer_cast( - anArcFeature->attribute(SketchPlugin_Arc::CENTER_ID())); - std::shared_ptr aStartAttr = std::dynamic_pointer_cast( - anArcFeature->attribute(SketchPlugin_Arc::START_ID())); - std::shared_ptr aEndAttr = std::dynamic_pointer_cast( - anArcFeature->attribute(SketchPlugin_Arc::END_ID())); - if (!aCenterAttr || !aStartAttr || !aEndAttr) - return; - std::shared_ptr aCenterPnt = aCenterAttr->pnt(); - std::shared_ptr aStartPnt = aStartAttr->pnt(); - std::shared_ptr aEndPnt = aEndAttr->pnt(); - - if (isFixed[2] && !isFixed[1]) - *aRadius = aCenterPnt->distance(aEndPnt); - else - *aRadius = aCenterPnt->distance(aStartPnt); - if (!anArcFeature->lastResult()) - return; - static std::shared_ptr OX(new GeomAPI_Dir2d(1.0, 0.0)); - std::shared_ptr aDir(new GeomAPI_Dir2d( - aStartPnt->xy()->decreased(aCenterPnt->xy()))); - *aStartAngle = OX->angle(aDir); - aDir = std::shared_ptr(new GeomAPI_Dir2d( - aEndPnt->xy()->decreased(aCenterPnt->xy()))); - *aEndAngle = OX->angle(aDir); - - // no need to constraint a fixed or a copied arc - if (theArc->group() == GID_OUTOFGROUP || anArcFeature->isCopy()) - return; - // No need to add constraints if they are already exist - std::map >::const_iterator - aFound = myArcConstraintMap.find(theArc); -// if (aFound != myArcConstraintMap.end()) -// return; - - // Prepare additional constraints to produce the arc - std::vector anArcConstraints; - std::shared_ptr anArcEnt = - std::dynamic_pointer_cast(theArc); - std::shared_ptr anArc = std::dynamic_pointer_cast(anArcEnt->entity()); - // Distances from center till start and end points are equal to radius - GCSConstraintPtr aNew = GCSConstraintPtr(new GCS::ConstraintP2PDistance( - anArc->center, anArc->start, anArc->rad)); -// aNew->setTag((int)(++myConstraintLastID)); - anArcConstraints.push_back(aNew); - aNew = GCSConstraintPtr(new GCS::ConstraintP2PDistance( - anArc->center, anArc->end, anArc->rad)); -// aNew->setTag((int)myConstraintLastID); - anArcConstraints.push_back(aNew); - // Angles of start and end points should be equal to given angles - aNew = GCSConstraintPtr(new GCS::ConstraintP2PAngle( - anArc->center, anArc->start, anArc->startAngle)); -// aNew->setTag((int)myConstraintLastID); - anArcConstraints.push_back(aNew); - aNew = GCSConstraintPtr(new GCS::ConstraintP2PAngle( - anArc->center, anArc->end, anArc->endAngle)); -// aNew->setTag((int)myConstraintLastID); - anArcConstraints.push_back(aNew); - - myArcConstraintMap[theArc] = anArcConstraints; + // create base constraints for the ellipse without adding them to solver + createEllipseConstraints(theEllipticArc, SolverPtr(), theConstraintID, theConstraints); + + ConstraintWrapperPtr& aConstraint = theConstraints[theEllipticArc]; + std::list anEllArcConstraints = aConstraint->constraints(); + + // constrain extremities of the elliptic arc + EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(theEllipticArc); + std::shared_ptr anArc = + std::dynamic_pointer_cast(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); } - -void PlaneGCSSolver_Storage::makeConstant(const EntityWrapperPtr& theEntity) +static void createBSplineConstraints( + const EntityWrapperPtr& theCurve, + const SolverPtr& theSolver, + const ConstraintID theConstraintID, + std::map& theConstraints) { - toggleEntity(theEntity, myParameters, myConst); - if (theEntity->type() == ENTITY_POINT) - updateCoincident(theEntity); + // set start and end point of B-spline equal to first and last pole correspondingly + EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(theCurve); + std::shared_ptr aBSpline = + std::dynamic_pointer_cast(anEdge->entity()); + if (aBSpline->periodic) + return; // additional constraints are not necessary + + std::list aBSplineConstraints; + + const std::map& anAdditional = anEdge->additionalAttributes(); + PointWrapperPtr aStartPoint = std::dynamic_pointer_cast( + 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( + 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::makeVariable(const EntityWrapperPtr& theEntity) +void PlaneGCSSolver_Storage::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity) { - toggleEntity(theEntity, myConst, myParameters); + 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); } -static void getParametersToMove(const EntityWrapperPtr& theEntity, std::set& theParamList) +void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity) { - const std::list aParams = theEntity->parameters(); - std::list::const_iterator aPIt = aParams.begin(); - for (; aPIt != aParams.end(); ++aPIt) - theParamList.insert( - std::dynamic_pointer_cast(*aPIt)->parameter()); - - const std::list aSubs = theEntity->subEntities(); - std::list::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. skip start and end points - ++aSIt; - // 3. take radius, start angle and end angle parameters - getParametersToMove(*(++aSIt), theParamList); - getParametersToMove(*(++aSIt), theParamList); - getParametersToMove(*(++aSIt), theParamList); - } else { - for (; aSIt != aSubs.end(); ++aSIt) - getParametersToMove(*aSIt, theParamList); + std::map::iterator + aFound = myAuxConstraintMap.find(theEntity); + if (aFound != myAuxConstraintMap.end()) { + mySketchSolver->removeConstraint(aFound->second->id()); + myAuxConstraintMap.erase(aFound); } } -void PlaneGCSSolver_Storage::toggleEntity( - const EntityWrapperPtr& theEntity, GCS::VEC_pD& theFrom, GCS::VEC_pD& theTo) +template +void adjustArcParametrization(ARCTYPE& theArc, bool theReversed) { - std::set aParamsToMove; - getParametersToMove(theEntity, aParamsToMove); - - GCS::VEC_pD::iterator anIt = theFrom.begin(); - while (anIt != theFrom.end()) { - if (aParamsToMove.find(*anIt) == aParamsToMove.end()) { - ++anIt; - continue; - } - - theTo.push_back(*anIt); - int aShift = int(anIt - theFrom.begin()); - theFrom.erase(anIt); - anIt = theFrom.begin() + aShift; + // 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::updateCoincident(const EntityWrapperPtr& thePoint) +void PlaneGCSSolver_Storage::adjustParametrizationOfArcs() { - CoincidentPointsMap::iterator anIt = myCoincidentPoints.begin(); - for (; anIt != myCoincidentPoints.end(); ++anIt) { - if (anIt->first == thePoint || anIt->second.find(thePoint) != anIt->second.end()) { - std::set aCoincident = anIt->second; - aCoincident.insert(anIt->first); - - const std::list& aBaseParams = thePoint->parameters(); - std::list aParams; - std::list::const_iterator aBaseIt, anUpdIt; - - std::set::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()); - } - - break; + std::map::iterator anIt = myAuxConstraintMap.begin(); + for (; anIt != myAuxConstraintMap.end(); ++anIt) { + EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(anIt->first); + std::shared_ptr anArc = std::dynamic_pointer_cast(anEdge->entity()); + if (anArc) + adjustArcParametrization(*anArc, anEdge->isReversed()); + else { + std::shared_ptr aEllArc = + std::dynamic_pointer_cast(anEdge->entity()); + if (aEllArc) + adjustArcParametrization(*aEllArc, anEdge->isReversed()); } } + + // update parameters of Middle point constraint for point on arc + std::map::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 >& 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 aSubs = theParentConstraint->entities(); - std::shared_ptr aPoint = aBuilder->point(aSubs.front()); - std::shared_ptr aLine = aBuilder->line(aSubs.back()); - return aLine->distance(aPoint) < tolerance; + std::map::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 >::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 anInvalidConstraints; + std::map::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::const_iterator anInvCIt = anInvalidConstraints.begin(); + for (; anInvCIt != anInvalidConstraints.end(); ++anInvCIt) + removeConstraint(*anInvCIt); + + // Remove invalid features + std::list anInvalidFeatures; + std::map::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 aNewCoincidence; - aNewCoincidence.insert(aParams[0]); - aNewCoincidence.insert(aParams[1]); - theCoincidentPoints.push_back(aNewCoincidence); - } + std::list::const_iterator anInvFIt = anInvalidFeatures.begin(); + for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt) + removeFeature(*anInvFIt); + + // Remove invalid attributes + std::list anInvalidAttributes; + std::map::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::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 aSolver = - std::dynamic_pointer_cast(theSolver); - if (!aSolver) - return; - aSolver->clear(); - - if (myExistArc) - processArcs(); - - // initialize constraints - std::map >::const_iterator - aCIt = myConstraintMap.begin(); - GCS::SET_I aTangentIDs; - std::list > aCoincidentPoints; - for (; aCIt != myConstraintMap.end(); ++aCIt) { - std::list::const_iterator aCWIt = aCIt->second.begin(); - for (; aCWIt != aCIt->second.end(); ++ aCWIt) { - std::shared_ptr aGCS = - std::dynamic_pointer_cast(*aCWIt); - std::list::const_iterator anIt = aGCS->constraints().begin(); - for (; anIt != aGCS->constraints().end(); ++anIt) - if (!isRedundant(*anIt, aGCS, aCoincidentPoints)) - aSolver->addConstraint(*anIt, aGCS->type()); - } - // 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 >::const_iterator - anArcIt = myArcConstraintMap.begin(); - for (; anArcIt != myArcConstraintMap.end(); ++anArcIt) { - std::vector::const_iterator anIt = anArcIt->second.begin(); - for (; anIt != anArcIt->second.end(); ++anIt) - aSolver->addConstraint(*anIt, CONSTRAINT_UNKNOWN); - } - // removed waste constraints - std::list::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 -bool isExternalAttribute(const AttributePtr& theAttribute) +static bool isExternalAttribute(const AttributePtr& theAttribute) { if (!theAttribute) return false; @@ -665,157 +590,119 @@ bool isExternalAttribute(const AttributePtr& theAttribute) return aSketchFeature.get() && aSketchFeature->isExternal(); } -void PlaneGCSSolver_Storage::refresh(bool theFixedOnly) const +static void addOwnerToSet(const AttributePtr& theAttribute, std::set& theFeatures) { - //blockEvents(true); + 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 anUpdatedFeatures; + std::map::const_iterator anIt = myAttributeMap.begin(); - std::list aParams; - std::list::const_iterator aParIt; 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 - bool isExternal = isExternalAttribute(anIt->first); - - // 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 + if (isExternalAttribute(anIt->first)) + continue; std::shared_ptr aPoint2D = std::dynamic_pointer_cast(anIt->first); if (aPoint2D) { - if ((isUpd[0] && fabs(aPoint2D->x() - aCoords[0]) > aTol) || - (isUpd[1] && fabs(aPoint2D->y() - aCoords[1]) > aTol) || isExternal) { - // 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; - // get coordinates of "master"-point - std::shared_ptr aMaster = aCoincIt != myCoincidentPoints.end() ? - std::dynamic_pointer_cast(aCoincIt->first->baseAttribute()) : - aPoint2D; - if (!isUpd[0] || isExternal) aCoords[0] = aMaster->x(); - if (!isUpd[1] || isExternal) aCoords[1] = aMaster->y(); - if (!isExternal) - aPoint2D->setValue(aCoords[0], aCoords[1]); - if (aCoincIt != myCoincidentPoints.end()) { - if (aMaster && !isExternalAttribute(aMaster)) - aMaster->setValue(aCoords[0], aCoords[1]); - std::set::const_iterator aSlaveIt = aCoincIt->second.begin(); - for (; aSlaveIt != aCoincIt->second.end(); ++aSlaveIt) { - aPoint2D = std::dynamic_pointer_cast((*aSlaveIt)->baseAttribute()); - if (aPoint2D && !isExternalAttribute(aPoint2D)) - aPoint2D->setValue(aCoords[0], aCoords[1]); - } + std::shared_ptr aPointWrapper = + std::dynamic_pointer_cast(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 aPointArray = + std::dynamic_pointer_cast(anIt->first); + if (aPointArray) { + std::shared_ptr anArrayWrapper = + std::dynamic_pointer_cast(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(anIt->first); - if (aScalar && !isExternal) { - if (isUpd[0] && fabs(aScalar->value() - aCoords[0]) > aTol) - aScalar->setValue(aCoords[0]); + if (aScalar) { + ScalarWrapperPtr aScalarWrapper = + std::dynamic_pointer_cast(anIt->second); + if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) { + aScalar->setValue(aScalarWrapper->value()); + addOwnerToSet(anIt->first, anUpdatedFeatures); + } + continue; + } + AttributeDoubleArrayPtr aRealArray = + std::dynamic_pointer_cast(anIt->first); + if (aRealArray) { + std::shared_ptr anArrayWrapper = + std::dynamic_pointer_cast(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::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 aBuilder = - std::dynamic_pointer_cast(PlaneGCSSolver_Builder::getInstance()); - - std::shared_ptr aMidPoint; - if (theBase->type() == ENTITY_LINE) { - std::shared_ptr aPoints[2]; - const std::list& aSubs = theBase->subEntities(); - std::list::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)); + std::map::const_iterator aFIt = myFeatureMap.begin(); + for (; aFIt != myFeatureMap.end(); ++aFIt) { + EdgeWrapperPtr anEdge = std::dynamic_pointer_cast(aFIt->second); + if (anEdge && anEdge->isDegenerated()) + return PlaneGCSSolver_Solver::STATUS_DEGENERATED; } - else if (theBase->type() == ENTITY_ARC) { - double theX, theY; - double anArcPoint[3][2]; - const std::list& aSubs = theBase->subEntities(); - std::list::const_iterator anIt = aSubs.begin(); - for (int i = 0; i < 3; ++i, ++anIt) { - std::shared_ptr 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 - aStartDir(new GeomAPI_Dir2d(anArcPoint[1][0], anArcPoint[1][1])); - std::shared_ptr - 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(new GeomAPI_XY(theX, theY)); - } - - if (!aMidPoint) - return EntityWrapperPtr(); + return PlaneGCSSolver_Solver::STATUS_OK; +} - std::list 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(aParameters.front())->parameter(); - aPnt->y = - std::dynamic_pointer_cast(aParameters.back())->parameter(); - EntityWrapperPtr aResult(new PlaneGCSSolver_PointWrapper(AttributePtr(), aPnt)); - aResult->setGroup(myGroupID); - aResult->setParameters(aParameters); +void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set& theFeatures) const +{ + std::set aFreeParams; + mySketchSolver->getFreeParameters(aFreeParams); + if (aFreeParams.empty()) + return; - update(aResult); - return aResult; + for (std::map::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; + } + } }