From 956324a569b5010a2486a8c8380648406b7b164c Mon Sep 17 00:00:00 2001 From: azv Date: Thu, 25 Aug 2016 14:33:08 +0300 Subject: [PATCH] Issue #1664: improve mechanism of removing coincidence --- src/SketchSolver/SketchSolver_Group.cpp | 6 +- src/SketchSolver/SketchSolver_Storage.cpp | 217 ++++++++++++++-------- src/SketchSolver/SketchSolver_Storage.h | 3 + 3 files changed, 151 insertions(+), 75 deletions(-) diff --git a/src/SketchSolver/SketchSolver_Group.cpp b/src/SketchSolver/SketchSolver_Group.cpp index 12161b658..9447f1e1e 100644 --- a/src/SketchSolver/SketchSolver_Group.cpp +++ b/src/SketchSolver/SketchSolver_Group.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -709,14 +710,15 @@ std::list SketchSolver_Group::selectApplicableFeatures(const std::se std::set::const_iterator anObjIter = theObjects.begin(); for (; anObjIter != theObjects.end(); ++anObjIter) { // Operate sketch itself and SketchPlugin features only. - // Also, the Fillet need to be skipped, because there are several separated constraints composing it. + // Also, the Fillet and Split need to be skipped, because there are several separated constraints composing it. FeaturePtr aFeature = std::dynamic_pointer_cast(*anObjIter); if (!aFeature) continue; std::shared_ptr aSketchFeature = std::dynamic_pointer_cast(aFeature); if ((aFeature->getKind() != SketchPlugin_Sketch::ID() && !aSketchFeature) || - aFeature->getKind() == SketchPlugin_ConstraintFillet::ID()) + aFeature->getKind() == SketchPlugin_ConstraintFillet::ID() || + aFeature->getKind() == SketchPlugin_ConstraintSplit::ID()) continue; // Find the place where to insert a feature diff --git a/src/SketchSolver/SketchSolver_Storage.cpp b/src/SketchSolver/SketchSolver_Storage.cpp index 6eab8dadd..4dc1800d1 100644 --- a/src/SketchSolver/SketchSolver_Storage.cpp +++ b/src/SketchSolver/SketchSolver_Storage.cpp @@ -469,6 +469,27 @@ bool SketchSolver_Storage::removeEntity(AttributePtr theAttribute) return false; } +// Merge groups containing given entities +static void mergeGroups(std::list >& theGroups, + const EntityWrapperPtr& theEntity1, const EntityWrapperPtr& theEntity2) +{ + std::list >::iterator aFound1 = theGroups.end(); + std::list >::iterator aFound2 = theGroups.end(); + std::list >::iterator anIt = theGroups.begin(); + for (; anIt != theGroups.end() && (aFound1 == theGroups.end() || aFound2 == theGroups.end()); + ++anIt) { + if (anIt->find(theEntity1) != anIt->end()) + aFound1 = anIt; + if (anIt->find(theEntity2) != anIt->end()) + aFound2 = anIt; + } + + if (aFound1 == aFound2 || aFound1 == theGroups.end() || aFound2 == theGroups.end()) + return; // nothing to merge + + aFound1->insert(aFound2->begin(), aFound2->end()); + theGroups.erase(aFound2); +} bool SketchSolver_Storage::removeCoincidence(ConstraintWrapperPtr theConstraint) { @@ -488,80 +509,148 @@ bool SketchSolver_Storage::removeCoincidence(ConstraintWrapperPtr theConstraint) if (aPtPtIt == myCoincidentPoints.end()) return true; // already removed - // Create new copies of coincident points - BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); - std::list aNewPoints; - for (aPIt = aPoints.begin(); aPIt != aPoints.end(); ++aPIt) - aNewPoints.push_back(aBuilder->createAttribute( - (*aPIt)->baseAttribute(), myGroupID, mySketchID)); - - // Find all points fallen out of group of coincident points - std::map aNotCoinc; - aNotCoinc[aPtPtIt->first] = EntityWrapperPtr(); + // Removing of coincidence may split this group of coincident point to several groups. + // Find all of them and also the points which become alone. + std::list< std::set > aCoincGroups; + std::set aGroup; + aGroup.insert(aPtPtIt->first); + aCoincGroups.push_back(aGroup); std::set::const_iterator aTempIt = aPtPtIt->second.begin(); - for (; aTempIt != aPtPtIt->second.end(); ++aTempIt) - aNotCoinc[*aTempIt] = EntityWrapperPtr(); + for (; aTempIt != aPtPtIt->second.end(); ++aTempIt) { + aGroup.clear(); + aGroup.insert(*aTempIt); + aCoincGroups.push_back(aGroup); + } + std::map >::iterator aConstrIt = myConstraintMap.begin(); - for (; aConstrIt != myConstraintMap.end(); ++aConstrIt) - if (aConstrIt->first->getKind() == SketchPlugin_ConstraintCoincidence::ID()) { - AttributeRefAttrPtr aRefAttr[2] = { - aConstrIt->first->refattr(SketchPlugin_Constraint::ENTITY_A()), - aConstrIt->first->refattr(SketchPlugin_Constraint::ENTITY_B()) - }; - AttributePtr anAttr[2]; - if (aConstrIt->first->data()->isValid()) { - if (!aRefAttr[0] || !aRefAttr[1]) - continue; - - for (int i = 0; i < 2; ++i) { - if (aRefAttr[i]->isObject()) { - FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object()); - if (!aFeature || (aFeature->getKind() != SketchPlugin_Point::ID() && - aFeature->getKind() != SketchPlugin_IntersectionPoint::ID())) - continue; - anAttr[i] = aFeature->attribute(SketchPlugin_Point::COORD_ID()); - } else - anAttr[i] = aRefAttr[i]->attr(); - } - } else { - // obtain attributes from the constraint wrapper - ConstraintWrapperPtr aWrapper = aConstrIt->second.front(); - anAttr[0] = aWrapper->entities().front()->baseAttribute(); - anAttr[1] = aWrapper->entities().back()->baseAttribute(); - } + for (; aConstrIt != myConstraintMap.end(); ++aConstrIt) { + if (aConstrIt->first->getKind() != SketchPlugin_ConstraintCoincidence::ID()) + continue; + + AttributeRefAttrPtr aRefAttr[2] = { + aConstrIt->first->refattr(SketchPlugin_Constraint::ENTITY_A()), + aConstrIt->first->refattr(SketchPlugin_Constraint::ENTITY_B()) + }; + AttributePtr anAttr[2]; + if (aConstrIt->first->data()->isValid()) { + if (!aRefAttr[0] || !aRefAttr[1]) + continue; + for (int i = 0; i < 2; ++i) { - std::map::iterator - aFound = myAttributeMap.find(anAttr[i]); - if (aFound != myAttributeMap.end()) - aNotCoinc.erase(aFound->second); + if (aRefAttr[i]->isObject()) { + FeaturePtr aFeature = ModelAPI_Feature::feature(aRefAttr[i]->object()); + if (!aFeature || (aFeature->getKind() != SketchPlugin_Point::ID() && + aFeature->getKind() != SketchPlugin_IntersectionPoint::ID())) + continue; + anAttr[i] = aFeature->attribute(SketchPlugin_Point::COORD_ID()); + } else + anAttr[i] = aRefAttr[i]->attr(); } + } else { + // obtain attributes from the constraint wrapper + // if SketchPlugin_Constraint has invalid data (already removed) + ConstraintWrapperPtr aWrapper = aConstrIt->second.front(); + anAttr[0] = aWrapper->entities().front()->baseAttribute(); + anAttr[1] = aWrapper->entities().back()->baseAttribute(); + } + + EntityWrapperPtr anEntities[2]; + for (int i = 0; i < 2; ++i) { + std::map::iterator + aFound = myAttributeMap.find(anAttr[i]); + if (aFound != myAttributeMap.end()) + anEntities[i] = aFound->second; } - if (aNotCoinc.empty()) + mergeGroups(aCoincGroups, anEntities[0], anEntities[1]); + } + + // Collect alone points and build them new instances + std::list aShutOffList; + BuilderPtr aBuilder = SketchSolver_Manager::instance()->builder(); + std::map aNotCoinc; + std::list >::iterator aGroupIt = aCoincGroups.begin(); + while (aGroupIt != aCoincGroups.end()) { + if (aGroupIt->size() == 1) { + EntityWrapperPtr aPoint = *aGroupIt->begin(); + aShutOffList.push_back(aPoint); + aNotCoinc[aPoint] = + aBuilder->createAttribute(aPoint->baseAttribute(), myGroupID, mySketchID); + std::list >::iterator aRemoveIt = aGroupIt++; + aCoincGroups.erase(aRemoveIt); + } else // point is not alone + ++aGroupIt; + } + + if (aNotCoinc.empty() && aCoincGroups.size() == 1) return false; - std::list::const_iterator aNewPIt; - for (aPIt = aPoints.begin(), aNewPIt = aNewPoints.begin(); - aPIt != aPoints.end(); ++aPIt, ++aNewPIt) { - if (aNotCoinc.find(*aPIt) != aNotCoinc.end()) - aNotCoinc[*aPIt] = *aNewPIt; + + // Find all features and constraints uses non-coincident points + replaceEntities(aNotCoinc); + + // Remove not coincident points and points in separated groups + if (!aCoincGroups.empty()) { + aGroupIt = aCoincGroups.begin(); + for (++aGroupIt; aGroupIt != aCoincGroups.end(); ++aGroupIt) + aShutOffList.insert(aShutOffList.end(), aGroupIt->begin(), aGroupIt->end()); + } + std::list::iterator aNotCIt = aShutOffList.begin(); + for (; aNotCIt != aShutOffList.end(); ++aNotCIt) { + if (aPtPtIt->second.size() <= 1) { + myCoincidentPoints.erase(aPtPtIt); + break; + } + if (aPtPtIt->first == *aNotCIt) { + std::set aSlaves = aPtPtIt->second; + EntityWrapperPtr aNewMaster = *aSlaves.begin(); + aSlaves.erase(aSlaves.begin()); + myCoincidentPoints.erase(aPtPtIt); + myCoincidentPoints[aNewMaster] = aSlaves; + aPtPtIt = myCoincidentPoints.find(aNewMaster); + } else + aPtPtIt->second.erase(*aNotCIt); + } + + // Create additional groups of coincident points + aGroupIt = aCoincGroups.begin(); + if (!aCoincGroups.empty()) + ++aGroupIt; + for (; aGroupIt != aCoincGroups.end(); ++aGroupIt) { + aNotCoinc.clear(); + std::set::iterator anEntIt = aGroupIt->begin(); + for (; anEntIt != aGroupIt->end(); ++anEntIt) { + aNotCoinc[*anEntIt] = + aBuilder->createAttribute((*anEntIt)->baseAttribute(), myGroupID, mySketchID); + } + // replace points by newly created + replaceEntities(aNotCoinc); + // set new group of coincident points + EntityWrapperPtr aMasterEnt = aNotCoinc.begin()->second; + std::map::iterator aNCIt = aNotCoinc.begin(); + for (++aNCIt; aNCIt != aNotCoinc.end(); ++aNCIt) + addCoincidentPoints(aMasterEnt, aNCIt->second); } - // Find all features and constraints uses coincident points - std::map::iterator aNotCIt; + return true; +} + +void SketchSolver_Storage::replaceEntities(const std::map& theChange) +{ std::set anUpdFeatures; + std::map::const_iterator aSubIt; std::map::iterator aFIt = myFeatureMap.begin(); for (; aFIt != myFeatureMap.end(); ++aFIt) { if (!aFIt->second) continue; // avoid not completed arcs - for (aNotCIt = aNotCoinc.begin(); aNotCIt != aNotCoinc.end(); ++aNotCIt) { - if (!aNotCIt->second || !::isUsed(aFIt->first, aNotCIt->first->baseAttribute())) + for (aSubIt = theChange.begin(); aSubIt != theChange.end(); ++aSubIt) { + if (!aSubIt->second || !::isUsed(aFIt->first, aSubIt->first->baseAttribute())) continue; std::list aSubs = aFIt->second->subEntities(); std::list::iterator aSIt = aSubs.begin(); bool isUpd = false; for (; aSIt != aSubs.end(); ++aSIt) - if (*aSIt == aNotCIt->first) { - (*aSIt)->update(aNotCIt->second); + if (*aSIt == aSubIt->first) { + (*aSIt)->update(aSubIt->second); (*aSIt)->setGroup(aFIt->second->group()); isUpd = true; } @@ -575,24 +664,6 @@ bool SketchSolver_Storage::removeCoincidence(ConstraintWrapperPtr theConstraint) std::set::iterator anUpdIt = anUpdFeatures.begin(); for (; anUpdIt != anUpdFeatures.end(); ++anUpdIt) update(EntityWrapperPtr(*anUpdIt)); - - // remove not coincident points - for (aNotCIt = aNotCoinc.begin(); aNotCIt != aNotCoinc.end(); ++aNotCIt) { - if (aPtPtIt->second.size() <= 1) { - myCoincidentPoints.erase(aPtPtIt); - break; - } - if (aPtPtIt->first == aNotCIt->first) { - std::set aSlaves = aPtPtIt->second; - EntityWrapperPtr aNewMaster = *aSlaves.begin(); - aSlaves.erase(aSlaves.begin()); - myCoincidentPoints.erase(aPtPtIt); - myCoincidentPoints[aNewMaster] = aSlaves; - aPtPtIt = myCoincidentPoints.find(aNewMaster); - } else - aPtPtIt->second.erase(aNotCIt->first); - } - return true; } bool SketchSolver_Storage::remove(ConstraintWrapperPtr theConstraint) diff --git a/src/SketchSolver/SketchSolver_Storage.h b/src/SketchSolver/SketchSolver_Storage.h index 9bc6aeadc..c8b1e7688 100644 --- a/src/SketchSolver/SketchSolver_Storage.h +++ b/src/SketchSolver/SketchSolver_Storage.h @@ -209,6 +209,9 @@ protected: /// \brief Find arcs without corresponding entity applicable for the solver and build them SKETCHSOLVER_EXPORT void processArcs(); + /// \brief Replace entities by others + void replaceEntities(const std::map& theChange); + private: /// \brief Find the normal of the sketch EntityWrapperPtr getNormal() const; -- 2.39.2