From 39ef1a52a944ed56ea80a208e3a89096ffc89dc8 Mon Sep 17 00:00:00 2001 From: mpv Date: Fri, 31 Oct 2014 10:32:50 +0300 Subject: [PATCH] Issue #208 : selection of edges and vertices on the sketch --- src/Model/Model_AttributeSelection.cpp | 266 +++++++++++++----- .../SketchSolver_ConstraintGroup.cpp | 2 +- 2 files changed, 195 insertions(+), 73 deletions(-) diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index aac5c3f08..dd360d258 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -28,8 +29,20 @@ #include #include #include +#include +#include using namespace std; +/// adeed to the index in the packed map to signalize that the vertex of edge is seleted +/// (multiplied by the index of the edge) +static const int kSTART_VERTEX_DELTA = 1000000; + +// on this label is stored: +// TNaming_NamedShape - selected shape +// TNaming_Naming - topological selection information (for the body) +// TDataStd_IntPackedMap - indexes of edges in composite element (for construction) +// TDataStd_Integer - type of the selected shape (for construction) +// TDF_Reference - from ReferenceAttribute, the context void Model_AttributeSelection::setValue(const ResultPtr& theContext, const boost::shared_ptr& theSubShape) @@ -96,84 +109,162 @@ bool Model_AttributeSelection::update() } else if (aContext->groupName() == ModelAPI_ResultConstruction::group()) { // construction: identification by the results indexes, recompute faces and // take the face that more close by the indexes - boost::shared_ptr aWirePtr = boost::dynamic_pointer_cast( + boost::shared_ptr aWirePtr = + boost::dynamic_pointer_cast( boost::dynamic_pointer_cast(aContext)->shape()); if (aWirePtr && aWirePtr->hasPlane()) { - // If this is a wire with plane defined thin it is a sketch-like object - std::list > aFaces; - GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(), - aWirePtr->dirY(), aWirePtr->norm(), aWirePtr, aFaces); - if (aFaces.empty()) // no faces, update can not work correctly - return false; - // if there is no edges indexes, any face can be used: take the first boost::shared_ptr aData = boost::dynamic_pointer_cast(owner()->data()); TDF_Label aLab = aData->label(); + // getting a type of selected shape + Handle(TDataStd_Integer) aTypeAttr; + if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) { + return false; + } + TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get()); + // selected indexes will be needed in each "if" Handle(TDataStd_IntPackedMap) aSubIds; boost::shared_ptr aNewSelected; - if (!aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0) { - aNewSelected = *(aFaces.begin()); - } else { // searching for most looks-like initial face by the indexes - // prepare edges of the current resut for the fast searching - TColStd_MapOfTransient allCurves; - FeaturePtr aContextFeature = owner()->document()->feature(aContext); - CompositeFeaturePtr aComposite = - boost::dynamic_pointer_cast(aContextFeature); - if (!aComposite) // must be composite at least for the current implementation + bool aNoIndexes = + !aLab.FindAttribute(TDataStd_IntPackedMap::GetID(), aSubIds) || aSubIds->Extent() == 0; + // for now working only with composite features + FeaturePtr aContextFeature = owner()->document()->feature(aContext); + CompositeFeaturePtr aComposite = + boost::dynamic_pointer_cast(aContextFeature); + if (!aComposite || aComposite->numberOfSubs() == 0) { + return false; + } + + if (aShapeType == TopAbs_FACE) { + // If this is a wire with plane defined thin it is a sketch-like object + std::list > aFaces; + GeomAlgoAPI_SketchBuilder::createFaces(aWirePtr->origin(), aWirePtr->dirX(), + aWirePtr->dirY(), aWirePtr->norm(), aWirePtr, aFaces); + if (aFaces.empty()) // no faces, update can not work correctly return false; - const int aSubNum = aComposite->numberOfSubs(); - for(int a = 0; a < aSubNum; a++) { - if (aSubIds->Contains(aComposite->subFeatureId(a))) { - FeaturePtr aSub = aComposite->subFeature(a); - const std::list >& aResults = aSub->results(); - std::list >::const_iterator aRes = aResults.cbegin(); - for(; aRes != aResults.cend(); aRes++) { - ResultConstructionPtr aConstr = - boost::dynamic_pointer_cast(*aRes); - if (aConstr->shape() && aConstr->shape()->isEdge()) { - const TopoDS_Shape& aResShape = aConstr->shape()->impl(); - TopoDS_Edge anEdge = TopoDS::Edge(aResShape); - if (!anEdge.IsNull()) { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - allCurves.Add(aCurve); + // if there is no edges indexes, any face can be used: take the first + boost::shared_ptr aNewSelected; + if (aNoIndexes) { + aNewSelected = *(aFaces.begin()); + } else { // searching for most looks-like initial face by the indexes + // prepare edges of the current resut for the fast searching + TColStd_MapOfTransient allCurves; + const int aSubNum = aComposite->numberOfSubs(); + for(int a = 0; a < aSubNum; a++) { + if (aSubIds->Contains(aComposite->subFeatureId(a))) { + FeaturePtr aSub = aComposite->subFeature(a); + const std::list >& aResults = aSub->results(); + std::list >::const_iterator aRes; + for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) { + ResultConstructionPtr aConstr = + boost::dynamic_pointer_cast(*aRes); + if (aConstr->shape() && aConstr->shape()->isEdge()) { + const TopoDS_Shape& aResShape = aConstr->shape()->impl(); + TopoDS_Edge anEdge = TopoDS::Edge(aResShape); + if (!anEdge.IsNull()) { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + allCurves.Add(aCurve); + } + } + } + } + } + // iterate new result faces and searching for these edges + std::list >::iterator aFacesIter = aFaces.begin(); + double aBestFound = 0; // best percentage of found edges + for(; aFacesIter != aFaces.end(); aFacesIter++) { + int aFound = 0, aNotFound = 0; + TopExp_Explorer anEdgesExp((*aFacesIter)->impl(), TopAbs_EDGE); + for(; anEdgesExp.More(); anEdgesExp.Next()) { + TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current()); + if (!anEdge.IsNull()) { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + if (allCurves.Contains(aCurve)) { + aFound++; + } else { + aNotFound++; } } } + if (aFound + aNotFound != 0) { + double aPercentage = double(aFound) / double(aFound + aNotFound); + if (aPercentage > aBestFound) { + aBestFound = aPercentage; + aNewSelected = *aFacesIter; + } + } } } - // iterate new result faces and searching for these edges - std::list >::iterator aFacesIter = aFaces.begin(); - double aBestFound = 0; // best percentage of found edges - for(; aFacesIter != aFaces.end(); aFacesIter++) { - int aFound = 0, aNotFound = 0; - TopExp_Explorer anEdgesExp((*aFacesIter)->impl(), TopAbs_EDGE); - for(; anEdgesExp.More(); anEdgesExp.Next()) { - TopoDS_Edge anEdge = TopoDS::Edge(anEdgesExp.Current()); - if (!anEdge.IsNull()) { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - if (allCurves.Contains(aCurve)) { - aFound++; - } else { - aNotFound++; + if (aNewSelected) { // store this new selection + selectConstruction(aContext, aNewSelected); + owner()->data()->sendAttributeUpdated(this); + return true; + } + } else if (aShapeType == TopAbs_EDGE) { + // just reselect the edge by the id + const int aSubNum = aComposite->numberOfSubs(); + for(int a = 0; a < aSubNum; a++) { + // if aSubIds take any, the first appropriate + if (aSubIds->IsEmpty() || aSubIds->Contains(aComposite->subFeatureId(a))) { + // found the appropriate feature + FeaturePtr aFeature = aComposite->subFeature(a); + std::list >::const_iterator aResIter = + aFeature->results().cbegin(); + for(;aResIter != aFeature->results().cend(); aResIter++) { + ResultConstructionPtr aRes = + boost::dynamic_pointer_cast(*aResIter); + if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found! + selectConstruction(aContext, aRes->shape()); + owner()->data()->sendAttributeUpdated(this); + return true; } } } - if (aFound + aNotFound != 0) { - double aPercentage = double(aFound) / double(aFound + aNotFound); - if (aPercentage > aBestFound) { - aBestFound = aPercentage; - aNewSelected = *aFacesIter; + } + } else if (aShapeType == TopAbs_VERTEX) { + // just reselect the vertex by the id of edge + const int aSubNum = aComposite->numberOfSubs(); + for(int a = 0; a < aSubNum; a++) { + // if aSubIds take any, the first appropriate + int aFeatureID = aComposite->subFeatureId(a); + if (aSubIds->IsEmpty() || aSubIds->Contains(aFeatureID)) { + // searching for deltas + int aVertexNum = 0; + if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 1; + else if (aSubIds->Contains(aFeatureID + kSTART_VERTEX_DELTA)) aVertexNum = 2; + // found the feature with appropriate edge + FeaturePtr aFeature = aComposite->subFeature(a); + std::list >::const_iterator aResIter = + aFeature->results().cbegin(); + for(;aResIter != aFeature->results().cend(); aResIter++) { + ResultConstructionPtr aRes = + boost::dynamic_pointer_cast(*aResIter); + if (aRes && aRes->shape()) { + if (aRes->shape()->isVertex() && aVertexNum == 0) { // found! + selectConstruction(aContext, aRes->shape()); + owner()->data()->sendAttributeUpdated(this); + return true; + } else if (aRes->shape()->isEdge() && aVertexNum > 0) { + const TopoDS_Shape& anEdge = aRes->shape()->impl(); + int aVIndex = 1; + for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) { + if (aVIndex == aVertexNum) { // found! + boost::shared_ptr aVertex(new GeomAPI_Shape); + aVertex->setImpl(new TopoDS_Shape(aVExp.Current())); + selectConstruction(aContext, aVertex); + owner()->data()->sendAttributeUpdated(this); + return true; + } + aVIndex++; + } + } + } } } } } - if (aNewSelected) { // store this new selection - selectConstruction(aContext, aNewSelected); - owner()->data()->sendAttributeUpdated(this); - return true; - } } } return false; // unknown case @@ -216,12 +307,20 @@ void Model_AttributeSelection::selectConstruction( TDF_Label aLab = aData->label(); // identify the reuslts of sub-object of the composite by edges const TopoDS_Shape& aSubShape = theSubShape->impl(); + // save type of the selected shape in integer attribute + TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType(); + TDataStd_Integer::Set(aLab, (int)aShapeType); + gp_Pnt aVertexPos; TColStd_MapOfTransient allCurves; - for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) { - TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current()); - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - allCurves.Add(aCurve); + if (aShapeType == TopAbs_VERTEX) { // compare positions + aVertexPos = BRep_Tool::Pnt(TopoDS::Vertex(aSubShape)); + } else { + for(TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE); anEdgeExp.More(); anEdgeExp.Next()) { + TopoDS_Edge anEdge = TopoDS::Edge(anEdgeExp.Current()); + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + allCurves.Add(aCurve); + } } // iterate and store the result ids of sub-elements Handle(TDataStd_IntPackedMap) aRefs = TDataStd_IntPackedMap::Set(aLab); @@ -234,17 +333,40 @@ void Model_AttributeSelection::selectConstruction( for(; aRes != aResults.cend(); aRes++) { ResultConstructionPtr aConstr = boost::dynamic_pointer_cast(*aRes); - if (aConstr->shape() && aConstr->shape()->isEdge()) { - const TopoDS_Shape& aResShape = aConstr->shape()->impl(); - TopoDS_Edge anEdge = TopoDS::Edge(aResShape); - if (!anEdge.IsNull()) { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); - if (allCurves.Contains(aCurve)) { - boost::shared_ptr aSubData = boost::dynamic_pointer_cast(aSub->data()); - TDF_Label aSubLab = aSubData->label(); + if (!aConstr->shape()) { + continue; + } + if (aShapeType == TopAbs_VERTEX) { + if (aConstr->shape()->isVertex()) { // compare vertices positions + const TopoDS_Shape& aVertex = aConstr->shape()->impl(); + gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVertex)); + if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) { aRefs->Add(aComposite->subFeatureId(a)); } + } else { // get first or last vertex of the edge: last is stored with negative sign + const TopoDS_Shape& anEdge = aConstr->shape()->impl(); + int aDelta = kSTART_VERTEX_DELTA; + for(TopExp_Explorer aVExp(anEdge, TopAbs_VERTEX); aVExp.More(); aVExp.Next()) { + gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(aVExp.Current())); + if (aPnt.IsEqual(aVertexPos, Precision::Confusion())) { + aRefs->Add(aComposite->subFeatureId(a)); + aRefs->Add(aDelta + aComposite->subFeatureId(a)); + break; + } + aDelta += kSTART_VERTEX_DELTA; + } + } + } else { + if (aConstr->shape()->isEdge()) { + const TopoDS_Shape& aResShape = aConstr->shape()->impl(); + TopoDS_Edge anEdge = TopoDS::Edge(aResShape); + if (!anEdge.IsNull()) { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + if (allCurves.Contains(aCurve)) { + aRefs->Add(aComposite->subFeatureId(a)); + } + } } } } diff --git a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp index bfecae21d..781edd8fe 100644 --- a/src/SketchSolver/SketchSolver_ConstraintGroup.cpp +++ b/src/SketchSolver/SketchSolver_ConstraintGroup.cpp @@ -567,7 +567,7 @@ Slvs_hEntity SketchSolver_ConstraintGroup::changeEntity( for (; aConstrIter != myConstraints.end(); aConstrIter++) if (aConstrIter->type == SLVS_C_WHERE_DRAGGED && aCoincident.find(aConstrIter->ptA) != aCoincident.end()) { - myNeedToSolve = true; + //myNeedToSolve = true; return aEntIter->second; } } -- 2.39.2