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.
#include <ModelAPI_Tools.h>
#include <ModelAPI_Session.h>
#include <ModelAPI_Validator.h>
+#include <ModelGeomAlgo_Shape.h>
#include <Events_InfoMessage.h>
#include <GeomAPI_Edge.h>
-#include <GeomAPI_PlanarEdges.h>
#include <GeomAPI_Pnt.h>
#include <GeomAPI_Vertex.h>
#include <GeomAlgoAPI_CompoundBuilder.h>
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<GeomShapePtr> aSubs = theShape->subShapes(theType);
- for (std::list<GeomShapePtr>::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
if (isSubOfComposite)
continue;
- // process results of the current feature
- const std::list<ResultPtr>& aResults = (*anIt)->results();
- for (std::list<ResultPtr>::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<GeomAPI_PlanarEdges> aSketchEdges =
- std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(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<ModelAPI_ResultConstruction>(*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;
}
}
aNewAttr->setID(id());
mySize->Set(aNewTag);
aNewAttr->selectSubShape(theType, thePoint);
+ if (selectionType().empty())
+ setSelectionType(aNewAttr->value()->shapeTypeStr());
owner()->data()->sendAttributeUpdated(this);
}
#include <ModelAPI_Feature.h>
#include <ModelAPI_Result.h>
+#include <ModelAPI_ResultConstruction.h>
+
+#include <GeomAPI_PlanarEdges.h>
+#include <GeomAPI_Pnt.h>
#ifdef WIN32
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<GeomShapePtr> aSubs = theShape->subShapes(theType);
+ for (std::list<GeomShapePtr>::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<ModelAPI_Feature>& theFeature,
+ const std::shared_ptr<GeomAPI_Pnt>& thePoint,
+ const GeomAPI_Shape::ShapeType& theShapeType,
+ std::shared_ptr<ModelAPI_Result>& theResult,
+ std::shared_ptr<GeomAPI_Shape>& theSubshape)
+ {
+ static const double TOLERANCE = 1.e-7;
+
+ theResult = ResultPtr();
+ const std::list<ResultPtr>& aResults = theFeature->results();
+ for (std::list<ResultPtr>::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<GeomAPI_PlanarEdges> aSketchEdges =
+ std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(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<ModelAPI_ResultConstruction>(*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
const std::shared_ptr<ModelAPI_Feature>& theFeature,
const GeomAPI_Shape::ShapeType& theType,
std::set<std::shared_ptr<ModelAPI_Result> >& 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<ModelAPI_Feature>& theFeature,
+ const std::shared_ptr<GeomAPI_Pnt>& thePoint,
+ const GeomAPI_Shape::ShapeType& theShapeType,
+ std::shared_ptr<ModelAPI_Result>& theResult,
+ std::shared_ptr<GeomAPI_Shape>& theSubshape);
}
#endif
GeomDataAPI
GeomAlgoAPI
ModelAPI
+ ModelGeomAlgo
)
ADD_DEFINITIONS(-DMODELHIGHAPI_EXPORTS -DWNT)
${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}
)
#include <ModelAPI_ResultPart.h>
#include <ModelAPI_Tools.h>
+#include <ModelGeomAlgo_Shape.h>
+
#include <PartSetPlugin_Part.h>
#include <OSD_OpenFile.hxx>
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<FeaturePtr> aFeatures = aDoc1->allFeatures();
+ if (aDoc1 != aDoc2) {
+ std::list<FeaturePtr> anAdditionalFeatures = aDoc2->allFeatures();
+ aFeatures.insert(aFeatures.end(), anAdditionalFeatures.begin(), anAdditionalFeatures.end());
+ }
+
+ CompositeFeaturePtr aLastCompositeFeature;
+
+ std::list<FeaturePtr>::const_iterator aFIt = aFeatures.begin();
+ while (aFIt != aFeatures.end() && *aFIt != theStartFeature) {
+ CompositeFeaturePtr aCompFeat = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(*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<ModelAPI_CompositeFeature>(*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<ModelAPI_AttributeSelection>& theAttrSelect)
{
// 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;
}
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)