#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>
+#include <GeomAlgoAPI_NExplode.h>
#include <TNaming_Selector.hxx>
#include <TNaming_NamedShape.hxx>
Standard_GUID kELLIPSE_CENTER1("f70df04c-3168-4dc9-87a4-f1f840c1275d");
// identifier of the selection of the second focus point of ellipse on edge
Standard_GUID kELLIPSE_CENTER2("1395ae73-8e02-4cf8-b204-06ff35873a32");
+// identifier of the weak naming index
+Standard_GUID kWEAK_NAMING("9dcdd9be-a3a9-46eb-9b16-1c957ab20142");
+// identifier of the weak naming sub-shape type
+Standard_GUID kWEAK_NAMING_SHAPETYPE("6b9cc709-e320-4a1f-9c42-df5622369ea7");
// prefix for the whole feature context identification
const static std::string kWHOLE_FEATURE = "all-in-";
aSelLab.ForgetAttribute(kCIRCLE_CENTER);
aSelLab.ForgetAttribute(kELLIPSE_CENTER1);
aSelLab.ForgetAttribute(kELLIPSE_CENTER2);
+ aSelLab.ForgetAttribute(kWEAK_NAMING);
+ aSelLab.ForgetAttribute(kWEAK_NAMING_SHAPETYPE);
bool isDegeneratedEdge = false;
// do not use the degenerated edge as a shape, a null context and shape is used in the case
}
}
+ if (aSelLab.IsAttribute(kWEAK_NAMING)) { // a weak naming is used
+ Handle(TDataStd_Integer) aWeakId;
+ aSelLab.FindAttribute(kWEAK_NAMING, aWeakId);
+ // get the context shape
+ GeomShapePtr aContextShape;
+ ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(context());
+ if (aBody.get()) {
+ aContextShape = aBody->shape();
+ } else {
+ ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
+ if (aResult) {
+ aContextShape = aResult->shape();
+ }
+ }
+ if (!aContextShape.get())
+ return GeomShapePtr();
+ Handle(TDataStd_Integer) aWeakShapeType;
+ aSelLab.FindAttribute(kWEAK_NAMING_SHAPETYPE, aWeakShapeType);
+ GeomAlgoAPI_NExplode aNExplode(aContextShape, GeomAPI_Shape::ShapeType(aWeakShapeType->Get()));
+ GeomShapePtr aValue = aNExplode.shape(aWeakId->Get());
+ return aValue;
+ }
+
Handle(TNaming_NamedShape) aSelection;
if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
TopoDS_Shape aSelShape = aSelection->Get();
}
if (aContext->groupName() == ModelAPI_ResultBody::group()) {
+ if (aSelLab.IsAttribute(kWEAK_NAMING)) { // a weak naming is used
+ Handle(TDataStd_Integer) aWeakId;
+ aSelLab.FindAttribute(kWEAK_NAMING, aWeakId);
+ // get the context shape
+ GeomShapePtr aContextShape;
+ ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
+ if (aBody.get()) {
+ aContextShape = aBody->shape();
+ } else {
+ ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(myRef.value());
+ if (aResult) {
+ aContextShape = aResult->shape();
+ }
+ }
+ if (!setInvalidIfFalse(aSelLab, aContextShape.get() != NULL)) // context shape not found
+ return false;
+ Handle(TDataStd_Integer) aWeakShapeType;
+ aSelLab.FindAttribute(kWEAK_NAMING_SHAPETYPE, aWeakShapeType);
+ GeomAlgoAPI_NExplode aNExplode(aContextShape, GeomAPI_Shape::ShapeType(aWeakShapeType->Get()));
+ GeomShapePtr aValue = aNExplode.shape(aWeakId->Get());
+ return setInvalidIfFalse(aSelLab, aValue.get() != NULL);
+ }
// body: just a named shape, use selection mechanism from OCCT
TNaming_Selector aSelector(aSelLab);
TopoDS_Shape anOldShape;
if (aEraseResults) // erase results without flash deleted and redisplay: do it after Select
aFeatureOwner->removeResults(0, false, false);
}
- aSel.Select(aNewSub, aNewContext);
+ bool aSelectorOk = true;
+ try {
+ aSel.Select(aNewSub, aNewContext);
+ } catch(...) {
+ aSelectorOk = false;
+ }
+ // face may become divided after the model update, so, new labels may be added to the scope
+ myScope.Clear();
+
+ // check that selection is correct, otherwise use weak naming solution
+ TDF_Label aSelLab = selectionLabel();
+ aSelLab.ForgetAttribute(kWEAK_NAMING);
+ Handle(TNaming_NamedShape) aSelectorShape;
+ if (aSelectorOk && aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aSelectorShape))
+ {
+ TopoDS_Shape aShape = aSelectorShape->Get();
+ if (aShape.IsNull() || aShape.ShapeType() != aNewSub.ShapeType())
+ aSelectorOk = false;
+ }
+ if (!aSelectorOk) { // weak naming identifier instead
+ GeomShapePtr aContextShape(new GeomAPI_Shape);
+ aContextShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aNewContext));
+ GeomShapePtr aValueShape(new GeomAPI_Shape);
+ aValueShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aNewSub));
+
+ GeomAlgoAPI_NExplode aNExplode(aContextShape, aValueShape->shapeType());
+ int anId = aNExplode.index(aValueShape);
+ if (anId) {
+ TDataStd_Integer::Set(aSelLab, kWEAK_NAMING, anId);
+ TDataStd_Integer::Set(aSelLab, kWEAK_NAMING_SHAPETYPE, int(aValueShape->shapeType()));
+ }
+ }
if (aEraseResults) { // flash after Select : in Groups it makes selection with shift working
static Events_Loop* aLoop = Events_Loop::loop();
return "";
}
- Model_SelectionNaming aSelNaming(selectionLabel());
+ TDF_Label aSelLab = selectionLabel();
+ Handle(TDataStd_Integer) aWeakId;
+ if (aSelLab.FindAttribute(kWEAK_NAMING, aWeakId)) { // a weak naming is used
+ std::ostringstream aNameStream;
+ aNameStream<<aCont->data()->name()<<"/weak_name_"<<aWeakId->Get();
+ return aNameStream.str();
+ }
+
+ Model_SelectionNaming aSelNaming(aSelLab);
std::string aResult = aSelNaming.namingName(
aCont, aSubSh, theDefaultName, owner()->document() != aCont->document());
if (aCenterType != NOT_CENTER) {
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;
+ // list of parent features
+ FeaturePtr anOwner = ModelAPI_Feature::feature(owner());
+ std::set<FeaturePtr> aParents = ModelAPI_Tools::getParents(anOwner);
+
+ int aSelectionIndex = 0;
GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::shapeTypeByStr(theType);
- GeomShapePtr aFoundSubShape;
+ 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;
+ }
+ }
+
+ std::list<ModelGeomAlgo_Shape::SubshapeOfResult> anAppropriate;
// collect features from PartSet and the current part
SessionPtr aSession = ModelAPI_Session::get();
// to find appropriate sub-shape
for (std::list<FeaturePtr>::const_reverse_iterator anIt = aFeatures.rbegin();
anIt != aFeatures.rend(); ++anIt) {
+ // selection cannot be linked to the parent features
+ if (aParents.find(*anIt) != aParents.end())
+ continue;
// check the feature is a part of composite feature (like sketch elements),
// then do not process it, it will be processed in scope of composite feature
bool isSubOfComposite = false;
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, anAppropriate)) {
+ std::list<ModelGeomAlgo_Shape::SubshapeOfResult>::iterator anApIt = anAppropriate.begin();
+ for (; aSelectionIndex > 0 && anApIt != anAppropriate.end(); --aSelectionIndex)
+ ++anApIt; // skip this shape, because one of the previous is selected
+
+ if (anApIt != anAppropriate.end()) {
+ if (anApIt->myCenterType == (int)ModelAPI_AttributeSelection::NOT_CENTER)
+ setValue(anApIt->myResult, anApIt->mySubshape);
+ else
+ setValueCenter(anApIt->myResult, anApIt->mySubshape->edge(),
+ (ModelAPI_AttributeSelection::CenterType)anApIt->myCenterType);
return;
}
}
reset();
}
+void Model_AttributeSelection::selectSubShape(const std::string& theType,
+ const std::string& theContextName, const int theIndex)
+{
+ // selection of context by name
+ //std::string aNamingContextName = theContextName + "/";
+ //selectSubShape(theType, aNamingContextName);
+ std::shared_ptr<Model_Document> aDoc =
+ std::dynamic_pointer_cast<Model_Document>(owner()->document());
+ if (aDoc.get()) {
+ bool aUnique = true;
+ std::string aContextName = theContextName;
+ std::string anEmptySub = "";
+ ResultPtr aContext = aDoc->findByName(aContextName, anEmptySub, aUnique);
+ //ResultPtr aContext = context();
+ if (aContext.get()) {
+ GeomShapePtr aContShape = aContext->shape();
+ if (aContShape.get()) {
+ GeomAlgoAPI_NExplode aNExp(aContShape, GeomAPI_Shape::shapeTypeByStr(theType));
+ GeomShapePtr aValue = aNExp.shape(theIndex);
+ if (aValue.get())
+ setValue(aContext, aValue);
+ }
+ }
+ }
+}
+
int Model_AttributeSelection::Id()
{
int anID = 0;
{
myParent = theParent;
}
+
+bool Model_AttributeSelection::isWeakNaming()
+{
+ return selectionLabel().IsAttribute(kWEAK_NAMING);
+}