X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FPlaneGCSSolver%2FPlaneGCSSolver_Storage.cpp;h=a5788f23a82f8e37224d769a52f4c91cf07bc89e;hb=82431fcacb9e3b6f5dfc882b01cd739160856d9e;hp=64d9c7fb5512754b5c7391c83411aa31ec72e23a;hpb=db767e51bfd7c4818abcdffbedb3dd78017b8463;p=modules%2Fshaper.git diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp index 64d9c7fb5..a5788f23a 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -1,14 +1,29 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D - -// File: PlaneGCSSolver_Storage.cpp -// Created: 14 Dec 2015 -// Author: Artem ZHIDKOV +// Copyright (C) 2014-2019 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 @@ -19,6 +34,7 @@ #include #include #include +#include #include #include @@ -29,9 +45,7 @@ static void constraintsToSolver(const ConstraintWrapperPtr& theConstraint, { const std::list& aConstraints = std::dynamic_pointer_cast(theConstraint)->constraints(); - std::list::const_iterator anIt = aConstraints.begin(); - for (; anIt != aConstraints.end(); ++anIt) - theSolver->addConstraint(*anIt); + theSolver->addConstraint(theConstraint->id(), aConstraints); } @@ -51,12 +65,9 @@ void PlaneGCSSolver_Storage::addConstraint( constraintsToSolver(theSolverConstraint, mySketchSolver); } -void PlaneGCSSolver_Storage::addTemporaryConstraint( +void PlaneGCSSolver_Storage::addMovementConstraint( const ConstraintWrapperPtr& theSolverConstraint) { - if (myConstraintMap.empty()) - return; // no need to process temporary constraints if there is no active constraint - // before adding movement constraint to solver, re-check its DOF if (mySketchSolver->dof() == 0) mySketchSolver->diagnose(); @@ -94,7 +105,7 @@ EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute( /// \brief Update value static bool updateValue(const double& theSource, double& theDest) { - static const double aTol = 1000. * tolerance; + static const double aTol = 1.e4 * tolerance; bool isUpdated = fabs(theSource - theDest) > aTol; if (isUpdated) theDest = theSource; @@ -125,6 +136,15 @@ static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity isUpdated = updateValue(aScalar->value(), aValue); if (isUpdated) aWrapper->setValue(aValue); + } else { + AttributeBooleanPtr aBoolean = + std::dynamic_pointer_cast(theAttribute); + if (aBoolean) { + BooleanWrapperPtr aWrapper = + std::dynamic_pointer_cast(theEntity); + isUpdated = aWrapper->value() != aBoolean->value(); + aWrapper->setValue(aBoolean->value()); + } } } @@ -138,7 +158,7 @@ static bool hasReference(std::shared_ptr theFeature, for (std::set::const_iterator aRefIt = aRefs.begin(); aRefIt != aRefs.end(); ++aRefIt) { FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); - if (anOwner->getKind() == theFeatureKind) + if (anOwner && anOwner->getKind() == theFeatureKind) return true; } return false; @@ -153,12 +173,12 @@ 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 - std::shared_ptr aSketchFeature = - std::dynamic_pointer_cast(theFeature); 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 @@ -176,17 +196,7 @@ bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce) // (do not want to add several copies of it while adding attributes) aRelated = createFeature(theFeature, &aBuilder); myFeatureMap[theFeature] = aRelated; - - const std::list& aConstraints = aBuilder.constraints(); - if (!aConstraints.empty()) { // the feature is arc - /// TODO: avoid this workaround - ConstraintWrapperPtr aWrapper( - new PlaneGCSSolver_ConstraintWrapper(aConstraints, CONSTRAINT_UNKNOWN)); - aWrapper->setId(++myConstraintLastID); - constraintsToSolver(aWrapper, mySketchSolver); - - myArcConstraintMap[myFeatureMap[theFeature]] = aWrapper; - } + createAuxiliaryConstraints(aRelated); isUpdated = true; } @@ -194,36 +204,28 @@ bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce) std::list::iterator anAttrIt = anAttributes.begin(); for (; anAttrIt != anAttributes.end(); ++anAttrIt) if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() || - (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId()) + (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId() || + (*anAttrIt)->attributeType() == ModelAPI_AttributeBoolean::typeId()) 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; + } + // send notification to listeners due to at least one attribute is changed if (sendNotify && isUpdated) notify(theFeature); // update arc - if (aRelated && aRelated->type() == ENTITY_ARC) { - /// TODO: this code should be shared with FeatureBuilder somehow - - std::shared_ptr anEntity = - std::dynamic_pointer_cast(aRelated); - std::shared_ptr anArc = std::dynamic_pointer_cast(anEntity->entity()); - - static std::shared_ptr OX(new GeomAPI_Dir2d(1.0, 0.0)); - std::shared_ptr aCenter( - new GeomAPI_Pnt2d(*anArc->center.x, *anArc->center.y)); - std::shared_ptr aStart( - new GeomAPI_Pnt2d(*anArc->start.x, *anArc->start.y)); - - *anArc->rad = aStart->distance(aCenter); - - std::shared_ptr aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy()))); - *anArc->startAngle = OX->angle(aDir); - - aDir = std::shared_ptr( - new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y())); - *anArc->endAngle = OX->angle(aDir); - } + if (aRelated) + PlaneGCSSolver_Tools::recalculateArcParameters(aRelated); return isUpdated; } @@ -263,6 +265,225 @@ bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce) return isUpdated; } +void PlaneGCSSolver_Storage::makeExternal(const EntityWrapperPtr& theEntity) +{ + if (theEntity->isExternal()) + return; + + removeAuxiliaryConstraints(theEntity); + + GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity); + mySketchSolver->removeParameters(aParameters); + theEntity->setExternal(true); + myNeedToResolve = true; +} + +void PlaneGCSSolver_Storage::makeNonExternal(const EntityWrapperPtr& theEntity) +{ + if (!theEntity->isExternal()) + return; + + GCS::SET_pD aParameters = PlaneGCSSolver_Tools::parameters(theEntity); + mySketchSolver->addParameters(aParameters); + theEntity->setExternal(false); + + createAuxiliaryConstraints(theEntity); + + myNeedToResolve = true; +} + + +static void createArcConstraints(const EntityWrapperPtr& theArc, + const SolverPtr& theSolver, + const ConstraintID theConstraintID, + std::map& theConstraints) +{ + 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; +} + +static void createEllipseConstraints( + const EntityWrapperPtr& theEllipse, + const SolverPtr& theSolver, + const ConstraintID theConstraintID, + std::map& theConstraints) +{ + 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; + + 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; +} + +static void createEllipticArcConstraints( + const EntityWrapperPtr& theEllipticArc, + const SolverPtr& theSolver, + const ConstraintID theConstraintID, + std::map& theConstraints) +{ + // 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::createAuxiliaryConstraints(const EntityWrapperPtr& theEntity) +{ + if (!theEntity || theEntity->isExternal()) + return; + + if (theEntity->type() == ENTITY_ARC) + createArcConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap); + else if (theEntity->type() == ENTITY_ELLIPSE) + createEllipseConstraints(theEntity, mySketchSolver, ++myConstraintLastID, myAuxConstraintMap); + else if (theEntity->type() == ENTITY_ELLIPTIC_ARC) { + createEllipticArcConstraints(theEntity, mySketchSolver, + ++myConstraintLastID, myAuxConstraintMap); + } +} + +void PlaneGCSSolver_Storage::removeAuxiliaryConstraints(const EntityWrapperPtr& theEntity) +{ + std::map::iterator + aFound = myAuxConstraintMap.find(theEntity); + if (aFound != myAuxConstraintMap.end()) { + mySketchSolver->removeConstraint(aFound->second->id()); + myAuxConstraintMap.erase(aFound); + } +} + +template +void adjustArcParametrization(ARCTYPE& theArc, bool theReversed) +{ + // tune start angle of the arc to be in [0, 2PI] + while (*theArc.startAngle < -PI) + *theArc.startAngle += 2.0 * PI; + while (*theArc.startAngle >= PI) + *theArc.startAngle -= 2.0 * PI; + // adjust end angle of the arc + if (theReversed) { + while (*theArc.endAngle > *theArc.startAngle) + *theArc.endAngle -= 2.0 * PI; + while (*theArc.endAngle + 2 * PI < *theArc.startAngle) + *theArc.endAngle += 2.0 * PI; + } + else { + while (*theArc.endAngle < *theArc.startAngle) + *theArc.endAngle += 2.0 * PI; + while (*theArc.endAngle > *theArc.startAngle + 2 * PI) + *theArc.endAngle -= 2.0 * PI; + } +} + +void PlaneGCSSolver_Storage::adjustParametrizationOfArcs() +{ + std::map::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::removeConstraint(ConstraintPtr theConstraint) @@ -321,12 +542,7 @@ void PlaneGCSSolver_Storage::removeInvalidEntities() aDestroyer.remove(aFIter->second); // remove invalid arc - std::map::iterator - aFound = myArcConstraintMap.find(aFIter->second); - if (aFound != myArcConstraintMap.end()) { - mySketchSolver->removeConstraint(aFound->second->id()); - myArcConstraintMap.erase(aFound); - } + removeAuxiliaryConstraints(aFIter->second); } std::list::const_iterator anInvFIt = anInvalidFeatures.begin(); for (; anInvFIt != anInvalidFeatures.end(); ++anInvFIt) @@ -389,6 +605,9 @@ void PlaneGCSSolver_Storage::refresh() const std::map::const_iterator anIt = myAttributeMap.begin(); for (; anIt != myAttributeMap.end(); ++anIt) { + if (!anIt->first->isInitialized()) + continue; + // the external feature always should keep the up to date values, so, // refresh from the solver is never needed if (isExternalAttribute(anIt->first)) @@ -424,3 +643,35 @@ void PlaneGCSSolver_Storage::refresh() const for (; aFIt != anUpdatedFeatures.end(); ++aFIt) notify(*aFIt); } + +PlaneGCSSolver_Solver::SolveStatus PlaneGCSSolver_Storage::checkDegeneratedGeometry() const +{ + 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; + } + return PlaneGCSSolver_Solver::STATUS_OK; +} + + +void PlaneGCSSolver_Storage::getUnderconstrainedGeometry(std::set& theFeatures) const +{ + std::set aFreeParams; + mySketchSolver->getFreeParameters(aFreeParams); + if (aFreeParams.empty()) + return; + + 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; + } + } +}