]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Issue #148 (reopened) fix: All features implicitly used by constraints are added...
authorazv <azv@opencascade.com>
Tue, 23 Sep 2014 10:32:23 +0000 (14:32 +0400)
committerazv <azv@opencascade.com>
Tue, 23 Sep 2014 10:38:02 +0000 (14:38 +0400)
src/GeomAPI/GeomAPI_Circ2d.cpp
src/GeomAlgoAPI/GeomAlgoAPI_SketchBuilder.cpp
src/SketchSolver/SketchSolver_ConstraintGroup.cpp
src/SketchSolver/SketchSolver_ConstraintGroup.h
src/SketchSolver/SketchSolver_ConstraintManager.cpp
src/SketchSolver/SketchSolver_ConstraintManager.h

index 65ef9b10786b77808f75544a3097b726e9bfdee9..d5a67b8f81ec27ffa666ca3400702d061d1d8b71 100644 (file)
@@ -61,28 +61,26 @@ const boost::shared_ptr<GeomAPI_Pnt2d> GeomAPI_Circ2d::project(
 {
   boost::shared_ptr<GeomAPI_Pnt2d> 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<gp_Pnt2d>();
 
-  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<GeomAPI_Pnt2d>(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<GeomAPI_Pnt2d>(
+        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<GeomAPI_Pnt2d>(
+        new GeomAPI_Pnt2d(aNewPoint.X(), aNewPoint.Y()));
   }
+
   return aResult;
 }
 
index b7ef59f5d68b549f8198d52b6b88fbc69404ff4c..20c3211ee1e402dd44cdbeeb20663c3d66e79874 100644 (file)
@@ -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<const TopoDS_Edge&>(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,
index 6b445b1873c554395f1b3c3c15fd5683c2e4b689..723ae3836baa22d39a04f2058c8a4c52de97c329 100644 (file)
@@ -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<SketchPlugin_Constraint> theConstraint) const
+    boost::shared_ptr<SketchPlugin_Feature> 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<ModelAPI_AttributeRefAttr> 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<boost::shared_ptr<ModelAPI_Attribute>> 
+      anAttrList = theFeature->data()->attributes(std::string());
+  std::list<boost::shared_ptr<ModelAPI_Attribute>>::const_iterator
+      anAttrIter = anAttrList.begin();
+  for ( ; anAttrIter != anAttrList.end(); anAttrIter++) {
+    boost::shared_ptr<ModelAPI_AttributeRefAttr> aCAttrRef =
+        boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(*anAttrIter);
+    if (!aCAttrRef || !aCAttrRef->isObject()) {
+      boost::shared_ptr<ModelAPI_Attribute> anAttr = 
+          aCAttrRef ? aCAttrRef->attr() : *anAttrIter;
+      if (myEntityAttrMap.find(anAttr) != myEntityAttrMap.end())
+        return true;
+    } else {
       ResultConstructionPtr aRC = boost::dynamic_pointer_cast<ModelAPI_ResultConstruction>(
           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<FeaturePtr, Slvs_hEntity>::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<Slvs_Entity>::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<Slvs_Constraint>::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
index 5d7123903abc50a099ba0a420e3f2b4784a72d07..34200bdbb309f63203c67a3acdc6b552eab0d042 100644 (file)
@@ -55,11 +55,11 @@ class SketchSolver_ConstraintGroup
    */
   bool changeConstraint(boost::shared_ptr<SketchPlugin_Constraint> 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<SketchPlugin_Constraint> theConstraint) const;
+  bool isInteract(boost::shared_ptr<SketchPlugin_Feature> 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<ModelAPI_Attribute> theEntity) const;
   void updateRelatedConstraints(boost::shared_ptr<ModelAPI_Feature> 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<ModelAPI_Attribute> 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
index ac0223064b1660cc6affe6befaf3885f3f131831..c0ade33a73680d44350a1919be5ebe31baed40f0 100644 (file)
@@ -69,9 +69,17 @@ void SketchSolver_ConstraintManager::processEvent(
         boost::dynamic_pointer_cast<ModelAPI_ObjectUpdatedMessage>(theMessage);
     std::set<ObjectPtr> aFeatures = anUpdateMsg->objects();
 
-    bool isModifiedEvt = theMessage->eventID()
+    bool isMovedEvt = theMessage->eventID()
         == Events_Loop::loop()->eventByName(EVENT_OBJECT_MOVED);
-    if (!isModifiedEvt) {
+    if (isMovedEvt) {
+      std::set<ObjectPtr>::iterator aFeatIter;
+      for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
+        boost::shared_ptr<SketchPlugin_Feature> aSFeature = 
+            boost::dynamic_pointer_cast<SketchPlugin_Feature>(*aFeatIter);
+        if (aSFeature)
+          updateEntity(aSFeature);
+      }
+    } else {
       std::set<ObjectPtr>::iterator aFeatIter;
       for (aFeatIter = aFeatures.begin(); aFeatIter != aFeatures.end(); aFeatIter++) {
         FeaturePtr aFeature = boost::dynamic_pointer_cast<ModelAPI_Feature>(*aFeatIter);
@@ -86,17 +94,11 @@ void SketchSolver_ConstraintManager::processEvent(
             changeWorkplane(aSketch);
           continue;
         }
-        boost::shared_ptr<SketchPlugin_Constraint> aConstraint = boost::dynamic_pointer_cast<
-            SketchPlugin_Constraint>(aFeature);
-        if (aConstraint)
-          changeConstraint(aConstraint);
-        else {
-          // Sketch plugin features can be only updated
-          boost::shared_ptr<SketchPlugin_Feature> aSFeature = boost::dynamic_pointer_cast<
-              SketchPlugin_Feature>(aFeature);
-          if (aSFeature)
-            updateEntity(aSFeature);
-        }
+        // Sketch plugin features can be only updated
+        boost::shared_ptr<SketchPlugin_Feature> 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<SketchPlugin_Constraint> theConstraint)
+bool SketchSolver_ConstraintManager::changeConstraintOrEntity(
+    boost::shared_ptr<SketchPlugin_Feature> theFeature)
 {
-  // Search the groups which this constraint touches
+  // Search the groups which this feature touches
   std::set<Slvs_hGroup> aGroups;
-  findGroups(theConstraint, aGroups);
+  findGroups(theFeature, aGroups);
+
+  boost::shared_ptr<SketchPlugin_Constraint> aConstraint = 
+      boost::dynamic_pointer_cast<SketchPlugin_Constraint>(theFeature);
 
   // Process the groups list
-  if (aGroups.size() == 0) {  // There are no groups applicable for this constraint => create new one
-    boost::shared_ptr<SketchPlugin_Feature> 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<SketchPlugin_Feature> 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<SketchSolver_ConstraintGroup*>::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<Slvs_hGroup>::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<SketchPlugin_Constraint> theConstraint,
+    boost::shared_ptr<SketchPlugin_Feature> theFeature,
     std::set<Slvs_hGroup>& theGroupIDs) const
 {
-  boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplaneForConstraint(theConstraint);
+  boost::shared_ptr<SketchPlugin_Feature> aWP = findWorkplane(theFeature);
 
   SketchSolver_ConstraintGroup* anEmptyGroup = 0;  // appropriate empty group for specified constraint
   std::vector<SketchSolver_ConstraintGroup*>::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<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
-    boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
+boost::shared_ptr<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWorkplane(
+    boost::shared_ptr<SketchPlugin_Feature> theFeature) const
 {
   // Already verified workplanes
   std::set<boost::shared_ptr<SketchPlugin_Feature> > aVerified;
@@ -334,7 +348,7 @@ boost::shared_ptr<SketchPlugin_Feature> SketchSolver_ConstraintManager::findWork
     std::list<ObjectPtr> aFeaturesList = aWPFeatures->list();
     std::list<ObjectPtr>::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);
   }
index 11e610b63372ff0ce7d832eaba1001f63f6a6ec3..b0aefd196ea3f8c9ddd8c36e09cd219e924a0d4e 100644 (file)
@@ -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<SketchPlugin_Constraint> theConstraint);
+  bool changeConstraintOrEntity(boost::shared_ptr<SketchPlugin_Feature> 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<SketchPlugin_Constraint> theConstraint,
+  void findGroups(boost::shared_ptr<SketchPlugin_Feature> theFeature,
                   std::set<Slvs_hGroup>& 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<SketchPlugin_Feature> findWorkplaneForConstraint(
-      boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const;
+  boost::shared_ptr<SketchPlugin_Feature> findWorkplane(
+      boost::shared_ptr<SketchPlugin_Feature> theFeature) const;
 
  private:
   static SketchSolver_ConstraintManager* _self;  ///< Self pointer to implement singleton functionality