X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FSketchSolver%2FPlaneGCSSolver%2FPlaneGCSSolver_Storage.cpp;h=0735867197a867dcca9b13ecdd2e7e4d73bcd476;hb=7d7d8eab2109542bd50a90a09c63f8fee1bfbb60;hp=4238120082f85a4d7efb4e646f40bb1b69f17070;hpb=a8cfbfb436c27ff96edd5c808e9a452c35cef207;p=modules%2Fshaper.git diff --git a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp index 423812008..073586719 100644 --- a/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp +++ b/src/SketchSolver/PlaneGCSSolver/PlaneGCSSolver_Storage.cpp @@ -5,729 +5,381 @@ // Author: Artem ZHIDKOV #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(); + std::list::const_iterator anIt = aConstraints.begin(); + for (; anIt != aConstraints.end(); ++anIt) + theSolver->addConstraint(*anIt, theConstraint->type()); +} + + +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); } +void PlaneGCSSolver_Storage::addTemporaryConstraint( + const ConstraintWrapperPtr& theSolverConstraint) +{ + if (myConstraintMap.empty()) + return; // no need to process temporary constraints if there is no active constraint -bool PlaneGCSSolver_Storage::update(ConstraintWrapperPtr theConstraint) + theSolverConstraint->setId(CID_MOVEMENT); + constraintsToSolver(theSolverConstraint, mySketchSolver); +} + + +EntityWrapperPtr PlaneGCSSolver_Storage::createFeature( + const FeaturePtr& theFeature, + PlaneGCSSolver_EntityBuilder* theBuilder) { - 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; - 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; - } - } - } + 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; +} - // Change ID of constraints - aConstraint->setId(++myConstraintLastID); - } +EntityWrapperPtr PlaneGCSSolver_Storage::createAttribute( + const AttributePtr& theAttribute, + PlaneGCSSolver_EntityBuilder* theBuilder) +{ + EntityWrapperPtr aResult = theBuilder->createAttribute(theAttribute); + if (aResult) + addEntity(theAttribute, aResult); + return aResult; +} +/// \brief Update value +static bool updateValue(const double& theSource, double& theDest) +{ + static const double aTol = 1000. * tolerance; + bool isUpdated = fabs(theSource - theDest) > aTol; + if (isUpdated) + theDest = theSource; return isUpdated; } /// \brief Update coordinates of the point or scalar using its base attribute -static bool updateValues(EntityWrapperPtr& theEntity) +static bool updateValues(AttributePtr& theAttribute, EntityWrapperPtr& theEntity) { 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); + std::dynamic_pointer_cast(theAttribute); if (aPoint2D) { - aCoord[0] = aPoint2D->x(); - aCoord[1] = aPoint2D->y(); + const GCSPointPtr& aGCSPoint = + std::dynamic_pointer_cast(theEntity)->point(); + isUpdated = updateValue(aPoint2D->x(), *(aGCSPoint->x)) || isUpdated; + isUpdated = updateValue(aPoint2D->y(), *(aGCSPoint->y)) || isUpdated; } else { - AttributeDoublePtr aScalar = std::dynamic_pointer_cast(anAttr); - if (aScalar) - aCoord[0] = aScalar->value(); - } - - std::list::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; -} - -bool PlaneGCSSolver_Storage::update(EntityWrapperPtr theEntity) -{ - if (theEntity->type() == ENTITY_SKETCH) - return true; // sketch is not necessary for PlaneGCS, so it is always says true - - bool isUpdated = false; - - if (theEntity->baseAttribute()) { - isUpdated = updateValues(theEntity); - if (isUpdated) - setNeedToResolve(true); - } - - // update parameters - std::list aParams = theEntity->parameters(); - std::list::iterator aPIt = aParams.begin(); - for (; aPIt != aParams.end(); ++aPIt) - isUpdated = update(*aPIt) || isUpdated; - - // update sub-entities - std::list aSubEntities = theEntity->subEntities(); - std::list::iterator aSIt = aSubEntities.begin(); - for (; aSIt != aSubEntities.end(); ++aSIt) - isUpdated = update(*aSIt) || isUpdated; - - // 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 = + AttributeDoublePtr aScalar = + std::dynamic_pointer_cast(theAttribute); + if (aScalar) { + ScalarWrapperPtr aWrapper = std::dynamic_pointer_cast(theEntity); - aScalar->setId(++myEntityLastID); - } else { - std::shared_ptr aGCSEnt = - std::dynamic_pointer_cast(theEntity); - aGCSEnt->setId(++myEntityLastID); + // There is possible angular value, which is converted between degrees and radians. + // So, we use its value instead of using direct pointer to value. + double aValue = aWrapper->value(); + isUpdated = updateValue(aScalar->value(), aValue); + if (isUpdated) + aWrapper->setValue(aValue); } } + return isUpdated; } -bool PlaneGCSSolver_Storage::update(ParameterWrapperPtr theParameter) +static bool isCopyInMulti(std::shared_ptr theFeature) { - std::shared_ptr aParam = - std::dynamic_pointer_cast(theParameter); - if (aParam->isProcessed()) + if (!theFeature) 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; -} - -bool PlaneGCSSolver_Storage::remove(EntityWrapperPtr theEntity) -{ - 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); - } + bool aResult = theFeature->isCopy(); + if (aResult) { + const std::set& aRefs = theFeature->data()->refsToMe(); + for (std::set::const_iterator aRefIt = aRefs.begin(); + aRefIt != aRefs.end() && aResult; ++aRefIt) { + FeaturePtr anOwner = ModelAPI_Feature::feature((*aRefIt)->owner()); + if (anOwner->getKind() == SketchPlugin_Projection::ID()) + aResult = false; } - if (theEntity->id() == myEntityLastID) - --myEntityLastID; } - return isFullyRemoved; + return aResult; } -bool PlaneGCSSolver_Storage::remove(ParameterWrapperPtr theParameter) +bool PlaneGCSSolver_Storage::update(FeaturePtr theFeature, bool theForce) { - 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); - } + bool isUpdated = false; + EntityWrapperPtr aRelated = entity(theFeature); + if (aRelated) // send signal to subscribers + notify(theFeature); + else { // Feature is not exist, create it + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(theFeature); + bool isCopy = isCopyInMulti(aSketchFeature); + // the feature is a copy in "Multi" constraint and does not used in other constraints + if (!theForce && isCopy && myFeatureMap.find(theFeature) == myFeatureMap.end()) + return false; + + // external feature processing + bool isExternal = (aSketchFeature && (aSketchFeature->isExternal() || isCopy)); + + 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; + + 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; } + isUpdated = true; } - return true; -} + std::list anAttributes = theFeature->data()->attributes(std::string()); + std::list::iterator anAttrIt = anAttributes.begin(); + for (; anAttrIt != anAttributes.end(); ++anAttrIt) + if ((*anAttrIt)->attributeType() == GeomDataAPI_Point2D::typeId() || + (*anAttrIt)->attributeType() == ModelAPI_AttributeDouble::typeId()) + isUpdated = update(*anAttrIt) || isUpdated; -void PlaneGCSSolver_Storage::addCoincidentPoints( - EntityWrapperPtr theMaster, EntityWrapperPtr theSlave) -{ - if (theMaster->type() != ENTITY_POINT || theSlave->type() != ENTITY_POINT) - 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; - } - } + // update arc + if (aRelated && aRelated->type() == ENTITY_ARC) { + /// TODO: this code should be shared with FeatureBuilder somehow - 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()); + std::shared_ptr anEntity = + std::dynamic_pointer_cast(aRelated); + std::shared_ptr anArc = std::dynamic_pointer_cast(anEntity->entity()); - //// Remove slave's parameters - //std::list::iterator aParIt = aSlaveParams.begin(); - //for (; aParIt != aSlaveParams.end(); ++aParIt) - // remove(*aParIt); + 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)); - aMasterFound->second.insert(aSlave); - } -} + *anArc->rad = aStart->distance(aCenter); + std::shared_ptr aDir(new GeomAPI_Dir2d(aStart->xy()->decreased(aCenter->xy()))); + *anArc->startAngle = OX->angle(aDir); -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); + aDir = std::shared_ptr( + new GeomAPI_Dir2d((*anArc->end.x) - aCenter->x(), (*anArc->end.y) - aCenter->y())); + *anArc->endAngle = OX->angle(aDir); } -} - -void PlaneGCSSolver_Storage::changeGroup(ParameterWrapperPtr theParam, const GroupID& theGroup) -{ - // TODO -} -void PlaneGCSSolver_Storage::verifyFixed() -{ - // TODO + return isUpdated; } -void PlaneGCSSolver_Storage::processArc(const EntityWrapperPtr& theArc) +bool PlaneGCSSolver_Storage::update(AttributePtr theAttribute, bool theForce) { - // no need to constraint a fixed arc - if (theArc->group() == GID_OUTOFGROUP) - return; - - // Calculate additional parameters necessary for PlaneGCS - const std::list& aSubs = theArc->subEntities(); - std::list::const_iterator aSubIt = aSubs.begin(); - while ((*aSubIt)->type() == ENTITY_POINT) // search scalar entities - ++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(); - - FeaturePtr anArcFeature = 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(); - - *aRadius = aCenterPnt->distance(aStartPnt); - if (!anArcFeature->lastResult()) - return; - std::shared_ptr anArcEdge = - std::dynamic_pointer_cast(anArcFeature->lastResult()->shape()); - if (!anArcEdge) - return; - anArcEdge->getRange(*aStartAngle, *aEndAngle); - - // 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 - 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 - 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; -} - + if (!theAttribute->isInitialized()) + return false; -void PlaneGCSSolver_Storage::makeConstant(const EntityWrapperPtr& theEntity) -{ - toggleEntity(theEntity, myParameters, myConst); - if (theEntity->type() == ENTITY_POINT) - updateCoincident(theEntity); -} + 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(); + } -void PlaneGCSSolver_Storage::makeVariable(const EntityWrapperPtr& theEntity) -{ - toggleEntity(theEntity, myConst, myParameters); -} + EntityWrapperPtr aRelated = entity(anAttribute); + if (!aRelated) { // Attribute does not exist, create it. + // First of all check if the parent feature exists. If not, add it. + FeaturePtr aFeature = ModelAPI_Feature::feature(anAttribute->owner()); + if (aFeature && myFeatureMap.find(aFeature) == myFeatureMap.end()) + return update(aFeature, theForce); // theAttribute has been processed while adding feature -static void getParametersToMove(const EntityWrapperPtr& theEntity, std::set& theParamList) -{ - 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. 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); +//// PlaneGCSSolver_AttributeBuilder aBuilder(this); +//// aRelated = createAttribute(anAttribute, &aBuilder); + return aRelated.get() != 0; } + + bool isUpdated = updateValues(anAttribute, aRelated); + if (isUpdated) + setNeedToResolve(true); + return isUpdated; } -void PlaneGCSSolver_Storage::toggleEntity( - const EntityWrapperPtr& theEntity, GCS::VEC_pD& theFrom, GCS::VEC_pD& theTo) -{ - 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; +bool PlaneGCSSolver_Storage::removeConstraint(ConstraintPtr theConstraint) +{ + std::map::iterator + aFound = myConstraintMap.find(theConstraint); + if (aFound != myConstraintMap.end()) { + ConstraintID anID = aFound->second->id(); + // Remove solver's constraints + mySketchSolver->removeConstraint(anID); + // Remove constraint + myConstraintMap.erase(aFound); + + if (anID != CID_MOVEMENT) + myNeedToResolve = true; + + // notify subscibers + notify(theConstraint); } + return true; } -void PlaneGCSSolver_Storage::updateCoincident(const EntityWrapperPtr& thePoint) +void PlaneGCSSolver_Storage::removeInvalidEntities() { - 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; + 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); + 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); + } + } + 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); + + // free memory occupied by parameters + removeParameters(aDestroyer.parametersToRemove()); + + /// TODO: Think on optimization of checking invalid features and attributes } -bool PlaneGCSSolver_Storage::isRedundant( - GCSConstraintPtr theCheckedConstraint, - ConstraintWrapperPtr theParentConstraint) const + +double* PlaneGCSSolver_Storage::createParameter() { - 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; - } - } + return mySketchSolver->createParameter(); +} - return false; +void PlaneGCSSolver_Storage::removeParameters(const GCS::SET_pD& theParams) +{ + mySketchSolver->removeParameters(theParams); } -void PlaneGCSSolver_Storage::initializeSolver(SolverPtr theSolver) +// indicates attribute containing in the external feature +bool isExternalAttribute(const AttributePtr& theAttribute) { - 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(); - 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)) - aSolver->addConstraint(*anIt); - } - } - // 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); - } - // removed waste constraints - std::list::const_iterator aRemIt = myRemovedConstraints.begin(); - for (; aRemIt != myRemovedConstraints.end(); ++aRemIt) - aSolver->removeConstraint(*aRemIt); - myRemovedConstraints.clear(); - // initialize unknowns - aSolver->setParameters(myParameters); + if (!theAttribute) + return false; + std::shared_ptr aSketchFeature = + std::dynamic_pointer_cast(theAttribute->owner()); + return aSketchFeature.get() && aSketchFeature->isExternal(); } -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::map::const_iterator anIt = myAttributeMap.begin(); - std::list aParams; - std::list::const_iterator aParIt; for (; anIt != myAttributeMap.end(); ++anIt) { - // the external feature always should keep the up to date values, so, + // 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 aSketchFeature = - std::dynamic_pointer_cast(anIt->first->owner()); - if (aSketchFeature.get() && aSketchFeature->isExternal()) - isExternal = true; - } - - // 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]) > 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( - aCoincIt->first->baseAttribute()); - if (aPoint2D) - aPoint2D->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) - 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); continue; } AttributeDoublePtr aScalar = std::dynamic_pointer_cast(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(anIt->second); + if (fabs(aScalar->value() - aScalarWrapper->value()) > aTol) + aScalar->setValue(aScalarWrapper->value()); continue; } } - - //blockEvents(false); -} - -EntityWrapperPtr PlaneGCSSolver_Storage::calculateMiddlePoint( - EntityWrapperPtr theBase, double theCoeff) -{ - 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)); - } - 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(); - - 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); - - update(aResult); - return aResult; }