From d21a0974f79da3df31bc2ccfd5becafb76e815d8 Mon Sep 17 00:00:00 2001 From: azv Date: Fri, 17 Aug 2018 14:59:37 +0300 Subject: [PATCH] Dump with geometrical selection Fix the selection of the "older" shape: if there are several shapes in the history, which satisfy the selected point criteria, but the selected one is not the last one. --- src/Model/Model_AttributeSelection.cpp | 105 ++++++--------------- src/Model/Model_AttributeSelectionList.cpp | 2 + src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp | 95 +++++++++++++++++++ src/ModelGeomAlgo/ModelGeomAlgo_Shape.h | 15 +++ src/ModelHighAPI/CMakeLists.txt | 2 + src/ModelHighAPI/ModelHighAPI_Dumper.cpp | 73 ++++++++++++-- src/ModelHighAPI/ModelHighAPI_Tools.cpp | 6 +- 7 files changed, 214 insertions(+), 84 deletions(-) diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp index 31bc8a0cf..787cc116f 100644 --- a/src/Model/Model_AttributeSelection.cpp +++ b/src/Model/Model_AttributeSelection.cpp @@ -36,9 +36,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -1067,43 +1067,35 @@ void Model_AttributeSelection::selectSubShape( reset(); } - -// Check the point is within shape's bounding box -static bool isPointWithinBB(const GeomPointPtr& thePoint, const GeomShapePtr& theShape) -{ - double aXMin, aXMax, aYMin, aYMax, aZMin, aZMax; - theShape->computeSize(aXMin, aYMin, aZMin, aXMax, aYMax, aZMax); - return thePoint->x() >= aXMin - Precision::Confusion() && - thePoint->x() <= aXMax + Precision::Confusion() && - thePoint->y() >= aYMin - Precision::Confusion() && - thePoint->y() <= aYMax + Precision::Confusion() && - thePoint->z() >= aZMin - Precision::Confusion() && - thePoint->z() <= aZMax + Precision::Confusion(); -} - -// Select sub-shape of the given type, which contains the given point -static GeomShapePtr findSubShape(const GeomShapePtr& theShape, - const GeomAPI_Shape::ShapeType& theType, - const GeomPointPtr& thePoint) -{ - std::list aSubs = theShape->subShapes(theType); - for (std::list::const_iterator aSubIt = aSubs.begin(); - aSubIt != aSubs.end(); ++aSubIt) { - if ((*aSubIt)->middlePoint()->distance(thePoint) < Precision::Confusion()) - return *aSubIt; - } - - // not found - return GeomShapePtr(); -} - void Model_AttributeSelection::selectSubShape(const std::string& theType, const GeomPointPtr& thePoint) { if (theType.empty() || !thePoint) return; + int aSelectionIndex = 0; GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::shapeTypeByStr(theType); + if (aType == GeomAPI_Shape::SHAPE) { + // possibly, the string consists of the type and the index, + // thus, try to separate them + size_t aUndersporePos = theType.find_first_of('_'); + if (aUndersporePos != std::string::npos) + aType = GeomAPI_Shape::shapeTypeByStr(theType.substr(0, aUndersporePos)); + + if (aType != GeomAPI_Shape::SHAPE) { + for (std::string::const_iterator aChar = theType.begin() + aUndersporePos + 1; + aChar != theType.end(); ++aChar) { + if (std::isdigit(*aChar)) + aSelectionIndex = aSelectionIndex * 10 + (*aChar - '0'); + else { + aSelectionIndex = 1; + break; + } + } + aSelectionIndex -= 1; + } + } + ResultPtr aFoundResult; GeomShapePtr aFoundSubShape; // collect features from PartSet and the current part @@ -1131,50 +1123,13 @@ void Model_AttributeSelection::selectSubShape(const std::string& theType, if (isSubOfComposite) continue; - // process results of the current feature - const std::list& aResults = (*anIt)->results(); - for (std::list::const_iterator aResIt = aResults.begin(); - aResIt != aResults.end(); ++aResIt) { - GeomShapePtr aCurShape = (*aResIt)->shape(); - // first of all, check the point is within bounding box of the result - if (!aCurShape || !isPointWithinBB(thePoint, aCurShape)) - continue; - // now, process all sub-shapes of the given type and check their inner points, - // but skip the case the selected type is COMPOUND and the shape is a list of sketch edges - // (it will be processed later) - std::shared_ptr aSketchEdges = - std::dynamic_pointer_cast(aCurShape); - if (aType != GeomAPI_Shape::COMPOUND || !aSketchEdges) - aFoundSubShape = findSubShape(aCurShape, aType, thePoint); - if (aFoundSubShape) { - setValue(*aResIt, aFoundSubShape); - return; - } - - // special case for ResultConstruction if the FACE is selected - ResultConstructionPtr aResConstr = - std::dynamic_pointer_cast(*aResIt); - if (aResConstr && aType >= GeomAPI_Shape::FACE) { - int aNbFaces = aResConstr->facesNum(); - for (int aFaceInd = 0; aFaceInd < aNbFaces; ++aFaceInd) { - GeomFacePtr aCurFace = aResConstr->face(aFaceInd); - // check the point is within bounding box of the face - if (!isPointWithinBB(thePoint, aCurFace)) - continue; - aFoundSubShape = findSubShape(aCurFace, aType, thePoint); - if (aFoundSubShape) { - setValue(*aResIt, aFoundSubShape); - return; - } - } - } - - // next special case: the full sketch is selected - // the selection type is a COMPOUND - if (aSketchEdges && - aSketchEdges->middlePoint()->distance(thePoint) < Precision::Confusion()) { - // select whole result - setValue(*aResIt, GeomShapePtr()); + // process results of the current feature to find appropriate sub-shape + if (ModelGeomAlgo_Shape::findSubshapeByPoint(*anIt, thePoint, aType, + aFoundResult, aFoundSubShape)) { + if (aSelectionIndex > 0) + --aSelectionIndex; // skip this shape, because one of the previous is selected + else { + setValue(aFoundResult, aFoundSubShape); return; } } diff --git a/src/Model/Model_AttributeSelectionList.cpp b/src/Model/Model_AttributeSelectionList.cpp index c7e852221..7575ca2f9 100644 --- a/src/Model/Model_AttributeSelectionList.cpp +++ b/src/Model/Model_AttributeSelectionList.cpp @@ -110,6 +110,8 @@ void Model_AttributeSelectionList::append(const GeomPointPtr& thePoint, const st aNewAttr->setID(id()); mySize->Set(aNewTag); aNewAttr->selectSubShape(theType, thePoint); + if (selectionType().empty()) + setSelectionType(aNewAttr->value()->shapeTypeStr()); owner()->data()->sendAttributeUpdated(this); } diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp b/src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp index f93dd9e48..ca7809b39 100644 --- a/src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp +++ b/src/ModelGeomAlgo/ModelGeomAlgo_Shape.cpp @@ -24,6 +24,10 @@ #include #include +#include + +#include +#include #ifdef WIN32 @@ -46,4 +50,95 @@ namespace ModelGeomAlgo_Shape theShapeResults.insert(aResult); } } + + // Check the point is within shape's bounding box + static bool isPointWithinBB(const GeomPointPtr& thePoint, + const GeomShapePtr& theShape, + const double theTolerance) + { + double aXMin, aXMax, aYMin, aYMax, aZMin, aZMax; + theShape->computeSize(aXMin, aYMin, aZMin, aXMax, aYMax, aZMax); + return thePoint->x() >= aXMin - theTolerance && thePoint->x() <= aXMax + theTolerance && + thePoint->y() >= aYMin - theTolerance && thePoint->y() <= aYMax + theTolerance && + thePoint->z() >= aZMin - theTolerance && thePoint->z() <= aZMax + theTolerance; + } + + // Select sub-shape of the given type, which contains the given point + static GeomShapePtr findSubShape(const GeomShapePtr& theShape, + const GeomAPI_Shape::ShapeType& theType, + const GeomPointPtr& thePoint, + const double theTolerance) + { + std::list aSubs = theShape->subShapes(theType); + for (std::list::const_iterator aSubIt = aSubs.begin(); + aSubIt != aSubs.end(); ++aSubIt) { + if ((*aSubIt)->middlePoint()->distance(thePoint) < theTolerance) + return *aSubIt; + } + + // not found + return GeomShapePtr(); + } + + bool findSubshapeByPoint(const std::shared_ptr& theFeature, + const std::shared_ptr& thePoint, + const GeomAPI_Shape::ShapeType& theShapeType, + std::shared_ptr& theResult, + std::shared_ptr& theSubshape) + { + static const double TOLERANCE = 1.e-7; + + theResult = ResultPtr(); + const std::list& aResults = theFeature->results(); + for (std::list::const_iterator aResIt = aResults.begin(); + aResIt != aResults.end(); ++aResIt) { + GeomShapePtr aCurShape = (*aResIt)->shape(); + // first of all, check the point is within bounding box of the result + if (!aCurShape || !isPointWithinBB(thePoint, aCurShape, TOLERANCE)) + continue; + // now, process all sub-shapes of the given type and check their inner points, + // but skip the case the selected type is COMPOUND and the shape is a list of sketch edges + // (it will be processed later) + std::shared_ptr aSketchEdges = + std::dynamic_pointer_cast(aCurShape); + if (theShapeType != GeomAPI_Shape::COMPOUND || !aSketchEdges) + theSubshape = findSubShape(aCurShape, theShapeType, thePoint, TOLERANCE); + if (theSubshape) { + theResult = *aResIt; + break; + } + + // special case for ResultConstruction if the FACE is selected + ResultConstructionPtr aResConstr = + std::dynamic_pointer_cast(*aResIt); + if (aResConstr && theShapeType >= GeomAPI_Shape::FACE) { + int aNbFaces = aResConstr->facesNum(); + for (int aFaceInd = 0; aFaceInd < aNbFaces; ++aFaceInd) { + GeomFacePtr aCurFace = aResConstr->face(aFaceInd); + // check the point is within bounding box of the face + if (!isPointWithinBB(thePoint, aCurFace, TOLERANCE)) + continue; + theSubshape = findSubShape(aCurFace, theShapeType, thePoint, TOLERANCE); + if (theSubshape) { + theResult = *aResIt; + break; + } + } + } + if (theResult) + break; + + // next special case: the full sketch is selected + // the selection type is a COMPOUND + if (aSketchEdges && + aSketchEdges->middlePoint()->distance(thePoint) < TOLERANCE) { + // select whole result + theResult = *aResIt; + theSubshape = GeomShapePtr(); + break; + } + } + + return (bool)theResult; + } } // namespace ModelGeomAlgo_Shape diff --git a/src/ModelGeomAlgo/ModelGeomAlgo_Shape.h b/src/ModelGeomAlgo/ModelGeomAlgo_Shape.h index cb0f7e243..e2fa4a175 100644 --- a/src/ModelGeomAlgo/ModelGeomAlgo_Shape.h +++ b/src/ModelGeomAlgo/ModelGeomAlgo_Shape.h @@ -39,6 +39,21 @@ namespace ModelGeomAlgo_Shape { const std::shared_ptr& theFeature, const GeomAPI_Shape::ShapeType& theType, std::set >& theShapeResults); + + /// Searches a sub-shape in the results of the given features, + /// which contains the given point. + /// \param[in] theFeature feature, which results are being processed + /// \param[in] thePoint selected point which identifies the shape + /// \param[in] theShapeType type of the selected shape + /// \param[out] theResult applicable result + /// \param[out] theSubshape sub-shape of the found result + /// \return \c true if the result and its applicable sub-shape are found + MODELGEOMALGO_EXPORT bool findSubshapeByPoint( + const std::shared_ptr& theFeature, + const std::shared_ptr& thePoint, + const GeomAPI_Shape::ShapeType& theShapeType, + std::shared_ptr& theResult, + std::shared_ptr& theSubshape); } #endif diff --git a/src/ModelHighAPI/CMakeLists.txt b/src/ModelHighAPI/CMakeLists.txt index 3af378807..8f0607feb 100644 --- a/src/ModelHighAPI/CMakeLists.txt +++ b/src/ModelHighAPI/CMakeLists.txt @@ -57,6 +57,7 @@ SET(PROJECT_LIBRARIES GeomDataAPI GeomAlgoAPI ModelAPI + ModelGeomAlgo ) ADD_DEFINITIONS(-DMODELHIGHAPI_EXPORTS -DWNT) @@ -84,6 +85,7 @@ INCLUDE_DIRECTORIES( ${PROJECT_SOURCE_DIR}/src/GeomAlgoAPI ${PROJECT_SOURCE_DIR}/src/GeomDataAPI ${PROJECT_SOURCE_DIR}/src/ModelAPI + ${PROJECT_SOURCE_DIR}/src/ModelGeomAlgo ${PROJECT_SOURCE_DIR}/src/PartSetPlugin ${OpenCASCADE_INCLUDE_DIR} ) diff --git a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp index 4e8152652..1cbee858c 100644 --- a/src/ModelHighAPI/ModelHighAPI_Dumper.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Dumper.cpp @@ -53,6 +53,8 @@ #include #include +#include + #include #include @@ -935,6 +937,46 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( return *this; } +static int possibleSelectionsByPoint(const GeomPointPtr& thePoint, + const GeomAPI_Shape::ShapeType& theType, + const FeaturePtr& theStartFeature, + const FeaturePtr& theEndFeature) +{ + DocumentPtr aDoc1 = theStartFeature->document(); + DocumentPtr aDoc2 = theEndFeature->document(); + + std::list aFeatures = aDoc1->allFeatures(); + if (aDoc1 != aDoc2) { + std::list anAdditionalFeatures = aDoc2->allFeatures(); + aFeatures.insert(aFeatures.end(), anAdditionalFeatures.begin(), anAdditionalFeatures.end()); + } + + CompositeFeaturePtr aLastCompositeFeature; + + std::list::const_iterator aFIt = aFeatures.begin(); + while (aFIt != aFeatures.end() && *aFIt != theStartFeature) { + CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast(*aFIt); + if (aCompFeat) + aLastCompositeFeature = aCompFeat; + ++aFIt; + } + + ResultPtr aResult; + GeomShapePtr aSubshape; + int aNbPossibleSelections = 0; + for (; aFIt != aFeatures.end() && *aFIt != theEndFeature; ++aFIt) { + if (aLastCompositeFeature && aLastCompositeFeature->isSub(*aFIt)) + continue; + CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast(*aFIt); + if (aCompFeat) + aLastCompositeFeature = aCompFeat; + + if (ModelGeomAlgo_Shape::findSubshapeByPoint(*aFIt, thePoint, theType, aResult, aSubshape)) + ++aNbPossibleSelections; + } + return aNbPossibleSelections; +} + ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( const std::shared_ptr& theAttrSelect) { @@ -957,20 +999,37 @@ ModelHighAPI_Dumper& ModelHighAPI_Dumper::operator<<( // how to dump selection: construction features are dumped by name always bool isDumpByGeom = myGeometricalSelection; + FeaturePtr aSelectedFeature; if (isDumpByGeom) { ResultPtr aRes = theAttrSelect->context(); if (aRes) { - FeaturePtr aFeat = ModelAPI_Feature::feature(aRes->data()->owner()); - if (aFeat) - isDumpByGeom = aFeat->isInHistory(); + aSelectedFeature = ModelAPI_Feature::feature(aRes->data()->owner()); + if (aSelectedFeature) + isDumpByGeom = aSelectedFeature->isInHistory(); } } - myDumpBuffer << "\"" << aShape->shapeTypeStr() << "\", "; - if (isDumpByGeom) - *this << aShape->middlePoint(); + myDumpBuffer << "\"" << aShape->shapeTypeStr(); + if (isDumpByGeom) { + GeomPointPtr aMiddlePoint = aShape->middlePoint(); + // calculate number of features, which could be selected by the same point + FeaturePtr anOwner = ModelAPI_Feature::feature(theAttrSelect->owner()); + int aNbPossibleSelections = + possibleSelectionsByPoint(aMiddlePoint, aShape->shapeType(), aSelectedFeature, anOwner); + + // produce the index if the number of applicable features is greater than 1 + std::string anIndex; + if (aNbPossibleSelections > 1) { + std::ostringstream anOutput; + anOutput << "_" << aNbPossibleSelections; + anIndex = anOutput.str(); + } + + myDumpBuffer << anIndex << "\", "; + *this << aMiddlePoint; + } else - myDumpBuffer << "\"" << theAttrSelect->namingName() << "\""; + myDumpBuffer << "\", \"" << theAttrSelect->namingName() << "\""; myDumpBuffer << ")"; return *this; } diff --git a/src/ModelHighAPI/ModelHighAPI_Tools.cpp b/src/ModelHighAPI/ModelHighAPI_Tools.cpp index 996e17676..87146a7a7 100644 --- a/src/ModelHighAPI/ModelHighAPI_Tools.cpp +++ b/src/ModelHighAPI/ModelHighAPI_Tools.cpp @@ -194,9 +194,11 @@ void fillAttribute(const std::list & theValue, theAttribute->clear(); if(!theValue.empty()) { - std::string aSelectionType; const ModelHighAPI_Selection& aSelection = theValue.front(); - theAttribute->setSelectionType(aSelection.shapeType()); + std::string aSelectionType = aSelection.shapeType(); + GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::shapeTypeByStr(aSelectionType); + if (aType != GeomAPI_Shape::SHAPE || aSelectionType == "SHAPE") + theAttribute->setSelectionType(aSelectionType); } for (auto it = theValue.begin(); it != theValue.end(); ++it) -- 2.39.2