From 747f357e1da638fc17654bf3e42ed7b1ace7b442 Mon Sep 17 00:00:00 2001 From: azv Date: Tue, 23 Sep 2014 14:32:23 +0400 Subject: [PATCH] Issue #148 (reopened) fix: All features implicitly used by constraints are added into constraint groups --- src/GeomAPI/GeomAPI_Circ2d.cpp | 34 ++++---- src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp | 15 ++++ .../SketchSolver_ConstraintGroup.cpp | 71 ++++++++++----- .../SketchSolver_ConstraintGroup.h | 10 +-- .../SketchSolver_ConstraintManager.cpp | 86 +++++++++++-------- .../SketchSolver_ConstraintManager.h | 26 +++--- 6 files changed, 147 insertions(+), 95 deletions(-) diff --git a/src/GeomAPI/GeomAPI_Circ2d.cpp b/src/GeomAPI/GeomAPI_Circ2d.cpp index 65ef9b107..d5a67b8f8 100644 --- a/src/GeomAPI/GeomAPI_Circ2d.cpp +++ b/src/GeomAPI/GeomAPI_Circ2d.cpp @@ -61,28 +61,26 @@ const boost::shared_ptr GeomAPI_Circ2d::project( { boost::shared_ptr aResult; if (!MY_CIRC2D) - return aResult; - - Handle(Geom2d_Circle) aCircle = new Geom2d_Circle(MY_CIRC2D->Axis(), MY_CIRC2D->Radius()); //(aCirc); + return aResult; + const gp_Pnt2d& aCenter = MY_CIRC2D->Location(); const gp_Pnt2d& aPoint = thePoint->impl(); - Geom2dAPI_ProjectPointOnCurve aProj(aPoint, aCircle); - Standard_Integer aNbPoint = aProj.NbPoints(); - double aX, anY; - if (aNbPoint > 0) { - double aMinDistance = 0, aDistance; - for (Standard_Integer j = 1; j <= aNbPoint; j++) { - gp_Pnt2d aNewPoint = aProj.Point(j); - aDistance = aNewPoint.Distance(aPoint); - if (!aMinDistance || aDistance < aMinDistance) { - aX = aNewPoint.X(); - anY = aNewPoint.Y(); - aMinDistance = aDistance; - aResult = boost::shared_ptr(new GeomAPI_Pnt2d(aX, anY)); - } - } + double aDist = aCenter.Distance(aPoint); + if (aDist < Precision::Confusion()) + return aResult; + + if (Abs(aDist - MY_CIRC2D->Radius()) < Precision::Confusion()) { + // Point on the circle + aResult = boost::shared_ptr( + new GeomAPI_Pnt2d(thePoint->x(), thePoint->y())); + } else { + gp_Dir2d aDir(aPoint.XY() - aCenter.XY()); + gp_XY aNewPoint = aCenter.XY() + aDir.XY() * MY_CIRC2D->Radius(); + aResult = boost::shared_ptr( + new GeomAPI_Pnt2d(aNewPoint.X(), aNewPoint.Y())); } + return aResult; } diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp index b7ef59f5d..20c3211ee 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp @@ -155,6 +155,8 @@ void GeomAlgoAPI_SketchBuilder::createFaces( while (aMapVE.Extent() > 0) { if (aCurVertex.IsNull()) return; + if (!aProcEdges.empty()) + aBindingEdge = aProcEdges.back(); findNextVertex(aCurVertex, aMapVE, aCurDir, aCurNorm, aNextVertex, aBindingEdge, aNextDir); aCurNorm = aNorm; @@ -466,6 +468,7 @@ void findNextVertex(const TopoDS_Vertex& theStartVertex, const gp_Dir& theStartDir, const gp_Dir& theNormal, TopoDS_Vertex& theNextVertex, TopoDS_Edge& theNextEdge, gp_Dir& theNextDir) { + theNextVertex = TopoDS_Vertex(); const BOPCol_ListOfShape& anEdgesList = theVertexEdgeMap.FindFromKey(theStartVertex); int anEdgesNum = anEdgesList.Extent(); BOPCol_ListOfShape::Iterator aEdIter(anEdgesList); @@ -505,6 +508,18 @@ void findNextVertex(const TopoDS_Vertex& theStartVertex, } } } + + // Probably there are two tangent edges. We will take the edge differs from current one + if (theNextVertex.IsNull() && anEdgesNum == 2) { + BOPCol_ListOfShape::Iterator aEdIter(anEdgesList); + if (aEdIter.Value() == theNextEdge) + aEdIter.Next(); + theNextEdge = static_cast(aEdIter.Value()); + TopoDS_Vertex aV1, aV2; + TopExp::Vertices(theNextEdge, aV1, aV2); + theNextVertex = theStartVertex.IsSame(aV1) ? aV2 : aV1; + theNextDir = getOuterEdgeDirection(theNextEdge, theNextVertex); + } } static void addEdgeToWire(const TopoDS_Edge& theEdge, const BRep_Builder& theBuilder, diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp index 6b445b187..723ae3836 100644 --- a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp @@ -123,22 +123,26 @@ bool SketchSolver_ConstraintGroup::isBaseWorkplane( // Purpose: verify are there any entities in the group used by given constraint // ============================================================================ bool SketchSolver_ConstraintGroup::isInteract( - boost::shared_ptr theConstraint) const + boost::shared_ptr theFeature) const { // Check the group is empty - if (myWorkplane.h != SLVS_E_UNKNOWN && myConstraints.empty()) + if (isEmpty()) return true; - // Go through constraint entities and verify if some of them already in the group - for (int i = 0; i < CONSTRAINT_ATTR_SIZE; i++) { - boost::shared_ptr aCAttrRef = boost::dynamic_pointer_cast< - ModelAPI_AttributeRefAttr>( - theConstraint->data()->attribute(SketchPlugin_Constraint::ATTRIBUTE(i))); - if (!aCAttrRef) - continue; - if (!aCAttrRef->isObject() && myEntityAttrMap.find(aCAttrRef->attr()) != myEntityAttrMap.end()) - return true; - if (aCAttrRef->isObject()) { // Obtain a base feature for the object + // Go through the attributes and verify if some of them already in the group + std::list> + anAttrList = theFeature->data()->attributes(std::string()); + std::list>::const_iterator + anAttrIter = anAttrList.begin(); + for ( ; anAttrIter != anAttrList.end(); anAttrIter++) { + boost::shared_ptr aCAttrRef = + boost::dynamic_pointer_cast(*anAttrIter); + if (!aCAttrRef || !aCAttrRef->isObject()) { + boost::shared_ptr anAttr = + aCAttrRef ? aCAttrRef->attr() : *anAttrIter; + if (myEntityAttrMap.find(anAttr) != myEntityAttrMap.end()) + return true; + } else { ResultConstructionPtr aRC = boost::dynamic_pointer_cast( aCAttrRef->object()); if (!aRC) @@ -297,6 +301,7 @@ bool SketchSolver_ConstraintGroup::changeConstraint( myConstraintMap[theConstraint] = aConstraint.h; int aConstrPos = Search(aConstraint.h, myConstraints); aConstrIter = myConstraints.begin() + aConstrPos; + myNeedToSolve = true; } checkConstraintConsistence(*aConstrIter); @@ -393,6 +398,8 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( // ============================================================================ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity(FeaturePtr theEntity) { + if (!theEntity->data()->isValid()) + return SLVS_E_UNKNOWN; // If the entity is already in the group, try to find it std::map::const_iterator aEntIter = myEntityFeatMap.find(theEntity); // defines that the entity already exists @@ -1027,6 +1034,22 @@ void SketchSolver_ConstraintGroup::removeConstraint( myConstraints.erase(myConstraints.begin() + aConstrPos); if (aCnstrToRemove == myConstrMaxID) myConstrMaxID--; + + // Find all entities which are based on these unused + std::vector::const_iterator anEntIter = myEntities.begin(); + for ( ; anEntIter != myEntities.end(); anEntIter++) + if (anEntIter->type == SLVS_E_LINE_SEGMENT || anEntIter->type == SLVS_E_CIRCLE || + anEntIter->type == SLVS_E_ARC_OF_CIRCLE) { + for (int i = 0; i < 4; i++) + if (anEntToRemove.find(anEntIter->point[i]) != anEntToRemove.end()) { + anEntToRemove.insert(anEntIter->h); + for (int j = 0; j < 4; j++) + if (anEntIter->param[j] != 0) + anEntToRemove.insert(anEntIter->point[j]); + break; + } + } + std::vector::const_iterator aConstrIter = myConstraints.begin(); for (; aConstrIter != myConstraints.end(); aConstrIter++) { Slvs_hEntity aEnts[] = { aConstrIter->ptA, aConstrIter->ptB, aConstrIter->entityA, aConstrIter @@ -1065,17 +1088,19 @@ void SketchSolver_ConstraintGroup::removeConstraint( unsigned int anEntPos = Search(*aRemIter, myEntities); if (anEntPos >= myEntities.size()) continue; - unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams); - if (aParamPos >= myParams.size()) - continue; - int aNbParams = 0; - while (myEntities[anEntPos].param[aNbParams] != 0) - aNbParams++; - if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID) - myParamMaxID -= aNbParams; - myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams); - if (*aRemIter == myEntityMaxID) - myEntityMaxID--; + if (myEntities[anEntPos].param[0] != 0) { + unsigned int aParamPos = Search(myEntities[anEntPos].param[0], myParams); + if (aParamPos >= myParams.size()) + continue; + int aNbParams = 0; + while (myEntities[anEntPos].param[aNbParams] != 0) + aNbParams++; + if (myEntities[anEntPos].param[aNbParams - 1] == myParamMaxID) + myParamMaxID -= aNbParams; + myParams.erase(myParams.begin() + aParamPos, myParams.begin() + aParamPos + aNbParams); + if (*aRemIter == myEntityMaxID) + myEntityMaxID--; + } myEntities.erase(myEntities.begin() + anEntPos); // Remove entity's ID from the lists of conincident points diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.h b/src/SketchSolver/SketchSolver_ConstraintGroup.h index 5d7123903..34200bdbb 100644 --- a/src/SketchSolver/SketchSolver_ConstraintGroup.h +++ b/src/SketchSolver/SketchSolver_ConstraintGroup.h @@ -55,11 +55,11 @@ class SketchSolver_ConstraintGroup */ bool changeConstraint(boost::shared_ptr theConstraint); - /** \brief Verifies the constraint uses the objects from this group - * \param[in] theConstraint constraint for verification of interaction - * \return \c true if the constrained objects are used in current group + /** \brief Verifies the feature attributes are used in this group + * \param[in] theFeature constraint or any other object for verification of interaction + * \return \c true if some of attributes are used in current group */ - bool isInteract(boost::shared_ptr theConstraint) const; + bool isInteract(boost::shared_ptr theFeature) const; /** \brief Verifies the specified feature is equal to the base workplane for this group * \param[in] theWorkplane the feature to be compared with base workplane @@ -108,7 +108,6 @@ class SketchSolver_ConstraintGroup void updateRelatedConstraints(boost::shared_ptr theEntity) const; void updateRelatedConstraints(boost::shared_ptr theFeature) const; - protected: /** \brief Adds or updates an entity in the group * * The parameters of entity will be parsed and added to the list of SolveSpace parameters. @@ -120,6 +119,7 @@ class SketchSolver_ConstraintGroup Slvs_hEntity changeEntity(boost::shared_ptr theEntity); Slvs_hEntity changeEntity(FeaturePtr theEntity); +protected: /** \brief Adds or updates a normal in the group * * Normal is a special entity in SolveSpace, which defines a direction in 3D and diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.cpp b/src/SketchSolver/SketchSolver_ConstraintManager.cpp index ac0223064..c0ade33a7 100644 --- a/src/SketchSolver/SketchSolver_ConstraintManager.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintManager.cpp @@ -69,9 +69,17 @@ void SketchSolver_ConstraintManager::processEvent( boost::dynamic_pointer_cast(theMessage); std::set aFeatures = anUpdateMsg->objects(); - bool isModifiedEvt = theMessage->eventID() + bool isMovedEvt = theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED); - if (!isModifiedEvt) { + if (isMovedEvt) { + std::set::iterator aFeatIter; + for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { + boost::shared_ptr aSFeature = + boost::dynamic_pointer_cast(*aFeatIter); + if (aSFeature) + updateEntity(aSFeature); + } + } else { std::set::iterator aFeatIter; for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) { FeaturePtr aFeature = boost::dynamic_pointer_cast(*aFeatIter); @@ -86,17 +94,11 @@ void SketchSolver_ConstraintManager::processEvent( changeWorkplane(aSketch); continue; } - boost::shared_ptr aConstraint = boost::dynamic_pointer_cast< - SketchPlugin_Constraint>(aFeature); - if (aConstraint) - changeConstraint(aConstraint); - else { - // Sketch plugin features can be only updated - boost::shared_ptr aSFeature = boost::dynamic_pointer_cast< - SketchPlugin_Feature>(aFeature); - if (aSFeature) - updateEntity(aSFeature); - } + // Sketch plugin features can be only updated + boost::shared_ptr aSFeature = boost::dynamic_pointer_cast< + SketchPlugin_Feature>(aFeature); + if (aSFeature) + changeConstraintOrEntity(aSFeature); } } @@ -168,36 +170,46 @@ bool SketchSolver_ConstraintManager::changeWorkplane( } // ============================================================================ -// Function: changeConstraint +// Function: changeConstraintOrEntity // Class: SketchSolver_Session -// Purpose: create/update the constraint and place it into appropriate group +// Purpose: create/update the constraint or the feature and place it into appropriate group // ============================================================================ -bool SketchSolver_ConstraintManager::changeConstraint( - boost::shared_ptr theConstraint) +bool SketchSolver_ConstraintManager::changeConstraintOrEntity( + boost::shared_ptr theFeature) { - // Search the groups which this constraint touches + // Search the groups which this feature touches std::set aGroups; - findGroups(theConstraint, aGroups); + findGroups(theFeature, aGroups); + + boost::shared_ptr aConstraint = + boost::dynamic_pointer_cast(theFeature); // Process the groups list - if (aGroups.size() == 0) { // There are no groups applicable for this constraint => create new one - boost::shared_ptr aWP = findWorkplaneForConstraint(theConstraint); + if (aGroups.size() == 0) { + // There are no groups applicable for this constraint => create new one + // The group will be created only for constraints, not for features + if (!aConstraint) return false; + boost::shared_ptr aWP = findWorkplane(aConstraint); if (!aWP) return false; SketchSolver_ConstraintGroup* aGroup = new SketchSolver_ConstraintGroup(aWP); - if (!aGroup->changeConstraint(theConstraint)) { + if (!aGroup->changeConstraint(aConstraint)) { delete aGroup; return false; } myGroups.push_back(aGroup); return true; - } else if (aGroups.size() == 1) { // Only one group => add constraint into it + } else if (aGroups.size() == 1) { // Only one group => add feature into it Slvs_hGroup aGroupId = *(aGroups.begin()); std::vector::iterator aGroupIter; for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if ((*aGroupIter)->getId() == aGroupId) - return (*aGroupIter)->changeConstraint(theConstraint); - } else if (aGroups.size() > 1) { // Several groups applicable for this constraint => need to merge them + if ((*aGroupIter)->getId() == aGroupId) { + // If the group is empty, the feature is not added (the constraint only) + if (!aConstraint && !(*aGroupIter)->isEmpty()) + return (*aGroupIter)->changeEntity(theFeature) != SLVS_E_UNKNOWN; + return (*aGroupIter)->changeConstraint(aConstraint); + } + } else if (aGroups.size() > 1) { // Several groups applicable for this feature => need to merge them std::set::const_iterator aGroupsIter = aGroups.begin(); // Search first group @@ -228,7 +240,9 @@ bool SketchSolver_ConstraintManager::changeConstraint( anOtherGroupIter = myGroups.begin() + aShiftOther; } - return (*aFirstGroupIter)->changeConstraint(theConstraint); + if (aConstraint) + return (*aFirstGroupIter)->changeConstraint(aConstraint); + return (*aFirstGroupIter)->changeEntity(theFeature) != SLVS_E_UNKNOWN; } // Something goes wrong @@ -289,18 +303,18 @@ void SketchSolver_ConstraintManager::updateEntity( // ============================================================================ // Function: findGroups // Class: SketchSolver_Session -// Purpose: search groups of entities interacting with given constraint +// Purpose: search groups of entities interacting with given feature // ============================================================================ void SketchSolver_ConstraintManager::findGroups( - boost::shared_ptr theConstraint, + boost::shared_ptr theFeature, std::set& theGroupIDs) const { - boost::shared_ptr aWP = findWorkplaneForConstraint(theConstraint); + boost::shared_ptr aWP = findWorkplane(theFeature); SketchSolver_ConstraintGroup* anEmptyGroup = 0; // appropriate empty group for specified constraint std::vector::const_iterator aGroupIter; for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++) - if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theConstraint)) { + if (aWP == (*aGroupIter)->getWorkplane() && (*aGroupIter)->isInteract(theFeature)) { if (!(*aGroupIter)->isEmpty()) theGroupIDs.insert((*aGroupIter)->getId()); else if (!anEmptyGroup) @@ -313,12 +327,12 @@ void SketchSolver_ConstraintManager::findGroups( } // ============================================================================ -// Function: findWorkplaneForConstraint +// Function: findWorkplane // Class: SketchSolver_Session -// Purpose: search workplane containing given constraint +// Purpose: search workplane containing given feature // ============================================================================ -boost::shared_ptr SketchSolver_ConstraintManager::findWorkplaneForConstraint( - boost::shared_ptr theConstraint) const +boost::shared_ptr SketchSolver_ConstraintManager::findWorkplane( + boost::shared_ptr theFeature) const { // Already verified workplanes std::set > aVerified; @@ -334,7 +348,7 @@ boost::shared_ptr SketchSolver_ConstraintManager::findWork std::list aFeaturesList = aWPFeatures->list(); std::list::const_iterator anIter; for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++) - if (*anIter == theConstraint) + if (*anIter == theFeature) return aWP; // workplane is found aVerified.insert(aWP); } diff --git a/src/SketchSolver/SketchSolver_ConstraintManager.h b/src/SketchSolver/SketchSolver_ConstraintManager.h index 11e610b63..b0aefd196 100644 --- a/src/SketchSolver/SketchSolver_ConstraintManager.h +++ b/src/SketchSolver/SketchSolver_ConstraintManager.h @@ -48,11 +48,11 @@ class SketchSolver_ConstraintManager : public Events_Listener SketchSolver_ConstraintManager(); ~SketchSolver_ConstraintManager(); - /** \brief Adds or updates a constraint in the suitable group - * \param[in] theConstraint constraint to be changed - * \return \c true if the constraint changed successfully + /** \brief Adds or updates a constraint or an entity in the suitable group + * \param[in] theFeature sketch feature to be changed + * \return \c true if the feature changed successfully */ - bool changeConstraint(boost::shared_ptr theConstraint); + bool changeConstraintOrEntity(boost::shared_ptr theFeature); /** \brief Removes a constraint from the manager * \param[in] theConstraint constraint to be removed @@ -84,19 +84,19 @@ class SketchSolver_ConstraintManager : public Events_Listener void resolveConstraints(); private: - /** \brief Searches list of groups which interact with specified constraint - * \param[in] theConstraint constraint to be found - * \param[out] theGroups list of group indexes interacted with constraint + /** \brief Searches list of groups which interact with specified feature + * \param[in] theFeature object to be found + * \param[out] theGroups list of group indexes interacted with the feature */ - void findGroups(boost::shared_ptr theConstraint, + void findGroups(boost::shared_ptr theFeature, std::set& theGroupIDs) const; - /** \brief Searches in the list of groups the workplane which constains specified constraint - * \param[in] theConstraint constraint to be found - * \return workplane containing the constraint + /** \brief Searches in the list of groups the workplane which constains specified feature + * \param[in] theFeature object to be found + * \return workplane containing the feature */ - boost::shared_ptr findWorkplaneForConstraint( - boost::shared_ptr theConstraint) const; + boost::shared_ptr findWorkplane( + boost::shared_ptr theFeature) const; private: static SketchSolver_ConstraintManager* _self; ///< Self pointer to implement singleton functionality -- 2.39.2