#include "Model_SelectionNaming.h"
#include "Model_Document.h"
+#include "Model_Objects.h"
#include <ModelAPI_Feature.h>
#include <Events_InfoMessage.h>
+#include <ModelAPI_Session.h>
+#include <ModelAPI_ResultPart.h>
+#include <ModelAPI_ResultConstruction.h>
+#include <ModelAPI_CompositeFeature.h>
+#include <ModelAPI_ResultBody.h>
#include <TopoDS_Iterator.hxx>
#include <TopoDS.hxx>
#include <TNaming_NamedShape.hxx>
#include <TNaming_Localizer.hxx>
#include <TDataStd_Name.hxx>
-#include <ModelAPI_ResultConstruction.h>
-#include <ModelAPI_CompositeFeature.h>
#include <TColStd_MapOfTransient.hxx>
#include <algorithm>
+#include <stdexcept>
#ifdef DEB_NAMING
#include <BRepTools.hxx>
#endif
-/// added to the index in the packed map to signalize that the vertex of edge is selected
-/// (multiplied by the index of the edge)
-static const int kSTART_VERTEX_DELTA = 1000000;
-
Model_SelectionNaming::Model_SelectionNaming(TDF_Label theSelectionLab)
{
myLab = theSelectionLab;
}
-
std::string Model_SelectionNaming::getShapeName(
- std::shared_ptr<Model_Document> theDoc, const TopoDS_Shape& theShape)
+ std::shared_ptr<Model_Document> theDoc, const TopoDS_Shape& theShape,
+ const bool theAddContextName)
{
std::string aName;
// check if the subShape is already in DF
if(!aNS.IsNull() && !aNS->IsEmpty()) { // in the document
if(aNS->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) {
aName = TCollection_AsciiString(anAttr->Get()).ToCString();
- if(!aName.empty()) {
- const TDF_Label& aLabel = theDoc->findNamingName(aName);
- /* MPV: the same shape with the same name may be duplicated on different labels (selection of the same construction object)
- if(!aLabel.IsEqual(aNS->Label())) {
- //aName.erase(); //something is wrong, to be checked!!!
- aName += "_SomethingWrong";
- return aName;
- }*/
-
+ // indexes are added to sub-shapes not primitives (primitives must not be located at the same label)
+ if(!aName.empty() && aNS->Evolution() != TNaming_PRIMITIVE && theAddContextName) {
+ const TDF_Label& aLabel = aNS->Label();//theDoc->findNamingName(aName);
static const std::string aPostFix("_");
TNaming_Iterator anItL(aNS);
for(int i = 1; anItL.More(); anItL.Next(), i++) {
break;
}
}
- }
+ }
+ if (theAddContextName && aName.find("/") == std::string::npos) { // searching for the context object
+ for(TDF_Label anObjL = aNS->Label(); anObjL.Depth() > 4; anObjL = anObjL.Father()) {
+ int aDepth = anObjL.Depth();
+ if (aDepth == 5 || aDepth == 7) {
+ ObjectPtr anObj = theDoc->objects()->object(anObjL);
+ if (anObj) {
+ aName = anObj->data()->name() + "/" + aName;
+ }
+ }
+ }
+ }
}
}
return aName;
}
-
-
bool isTrivial (const TopTools_ListOfShape& theAncestors, TopTools_IndexedMapOfShape& theSMap)
{
// a trivial case: F1 & F2, aNumber = 1, i.e. intersection gives 1 edge.
#endif
std::shared_ptr<Model_Document> aDoc =
std::dynamic_pointer_cast<Model_Document>(theContext->document());
+ if (theContext->groupName() == ModelAPI_ResultPart::group()) {
+ ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(theContext);
+ int anIndex;
+ return aPart->data()->name() + "/" + aPart->nameInPart(theSubSh, anIndex);
+ }
+
+ // add the result name to the name of the shape (it was in BodyBuilder, but did not work on Result rename)
+ bool isNeedContextName = theContext->shape().get() && !theContext->shape()->isEqual(theSubSh);
// check if the subShape is already in DF
- aName = getShapeName(aDoc, aSubShape);
+ aName = getShapeName(aDoc, aSubShape, isNeedContextName);
if(aName.empty() ) { // not in the document!
TopAbs_ShapeEnum aType = aSubShape.ShapeType();
switch (aType) {
// build name of the sub-shape Edge
for(int i=1; i <= aSMap.Extent(); i++) {
const TopoDS_Shape& aFace = aSMap.FindKey(i);
- std::string aFaceName = getShapeName(aDoc, aFace);
+ std::string aFaceName = getShapeName(aDoc, aFace, isNeedContextName);
if(i == 1)
aName = aFaceName;
else
}
TopTools_ListIteratorOfListOfShape itl(aListOfNbs);
for (;itl.More();itl.Next()) {
- std::string aFaceName = getShapeName(aDoc, itl.Value());
+ std::string aFaceName = getShapeName(aDoc, itl.Value(), isNeedContextName);
aName += "&" + aFaceName;
}
}
TopTools_ListIteratorOfListOfShape itl(aListE);
for (int i = 1;itl.More();itl.Next(),i++) {
const TopoDS_Shape& anEdge = itl.Value();
- std::string anEdgeName = getShapeName(aDoc, anEdge);
+ std::string anEdgeName = getShapeName(aDoc, anEdge, isNeedContextName);
if (anEdgeName.empty()) { // edge is not in DS, trying by faces anyway
isByFaces = true;
aName.clear();
TopTools_ListIteratorOfListOfShape itl(aList);
for (int i = 1;itl.More();itl.Next(),i++) {
const TopoDS_Shape& aFace = itl.Value();
- std::string aFaceName = getShapeName(aDoc, aFace);
+ std::string aFaceName = getShapeName(aDoc, aFace, isNeedContextName);
if(i == 1)
aName = aFaceName;
else
}
break;
}
- // register name
- // aDoc->addNamingName(selectionLabel(), aName);
- // the selected sub-shape will not be shared and as result it will not require registration
}
+
return aName;
}
if (n == std::string::npos) n = 0;
std::string aSubString = theSubShapeName.substr(n + 1);
n = aSubString.rfind('_');
- if (n == std::string::npos) return aSelection;
- aSubString = aSubString.substr(n+1);
- int indx = atoi(aSubString.c_str());
+ int indx;
+ if (n == std::string::npos) {// for primitives this is a first
+ indx = 1;
+ } else {
+ aSubString = aSubString.substr(n+1);
+ indx = atoi(aSubString.c_str());
+ }
TNaming_Iterator anItL(theNS);
for(int i = 1; anItL.More(); anItL.Next(), i++) {
const std::string& theSubShapeName, std::shared_ptr<Model_Document> theDoc)
{
TopoDS_Shape aFace;
- std::string::size_type n, nb = theSubShapeName.rfind('/');
- if (nb == std::string::npos) nb = 0;
- std::string aSubString = theSubShapeName.substr(nb + 1);
- n = aSubString.rfind('_');
- if (n != std::string::npos) {
- std::string aSubStr2 = aSubString.substr(0, n);
- aSubString = theSubShapeName.substr(0, nb + 1);
- aSubString = aSubString + aSubStr2;
- } else
- aSubString = theSubShapeName;
-
- const TDF_Label& aLabel = theDoc->findNamingName(aSubString);
+ //std::string::size_type n, nb = theSubShapeName.rfind('/');
+ //if (nb == std::string::npos) nb = 0;
+ //std::string aSubString = theSubShapeName.substr(nb + 1);
+ std::string aSubString = theSubShapeName;
+
+ TDF_Label aLabel = theDoc->findNamingName(aSubString);
+ if (aLabel.IsNull()) { // try to remove additional artificial suffix
+ std::string::size_type n = aSubString.rfind('_');
+ if (n != std::string::npos) {
+ aSubString = aSubString.substr(0, n);
+ aLabel = theDoc->findNamingName(aSubString);
+ }
+ }
if(aLabel.IsNull()) return aFace;
Handle(TNaming_NamedShape) aNS;
if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
} else {
int anOrientation = 1; // default
if (theOriented) { // here must be a symbol in the end of digit 'f' or 'r'
- const char aSymbol = anID.back();
- if (aSymbol == 'r') anOrientation = -1;
- anID.pop_back();
+ std::string::iterator aSymbol = anID.end() - 1;
+ if (*aSymbol == 'r') anOrientation = -1;
+ anID.erase(aSymbol); // remove last symbol
}
// check start/end symbols
- if (anID.back() == 's') {
+ std::string::iterator aBack = anID.end() - 1;
+ if (*aBack == 's') {
anOrientation *= 2;
- anID.pop_back();
- } else if (anID.back() == 'e') {
+ anID.erase(aBack); // remove last symbol
+ } else if (*aBack == 'e') {
anOrientation *= 3;
- anID.pop_back();
+ anID.erase(aBack); // remove last symbol
}
if (aNames.find(anID) != aNames.end()) {
/// produces theEdge orientation relatively to theContext face
int Model_SelectionNaming::edgeOrientation(const TopoDS_Shape& theContext, TopoDS_Edge& theEdge)
{
- if (theContext.ShapeType() != TopAbs_FACE)
+ if (theContext.ShapeType() != TopAbs_FACE && theContext.ShapeType() != TopAbs_WIRE)
return 0;
- TopoDS_Face aContext = TopoDS::Face(theContext);
if (theEdge.Orientation() == TopAbs_FORWARD)
return 1;
if (theEdge.Orientation() == TopAbs_REVERSED)
aName.erase(std::remove(aName.begin(), aName.end(), '&'), aName.end());
// remove the last 's', 'e', 'f' and 'r' symbols: they are used as markers of start/end/forward/rewersed indicators
static const std::string aSyms("sefr");
- while(aSyms.find(aName.back()) != std::string::npos) {
- aName.pop_back();
+ std::string::iterator aSuffix = aName.end() - 1;
+ while(aSyms.find(*aSuffix) != std::string::npos) {
+ --aSuffix;
}
+ aName.erase(aSuffix + 1, aName.end());
+
if (theEdgeVertexPos == 1) {
aName += "s"; // start
} else if (theEdgeVertexPos == 2) {
{
if(theSubShapeName.empty() || theType.empty()) return false;
TopAbs_ShapeEnum aType = translateType(theType);
- std::string aContName = getContextName(theSubShapeName);
+
+ // check that it was selected in another document
+ size_t aSlash = theSubShapeName.find("/");
+ std::string aSubShapeName = theSubShapeName;
+ std::shared_ptr<Model_Document> aDoc = theDoc;
+ if (aSlash != std::string::npos) {
+ std::string aDocName = theSubShapeName.substr(0, aSlash);
+ DocumentPtr aRootDoc = ModelAPI_Session::get()->moduleDocument();
+ if (aDocName == aRootDoc->kind()) {
+ aDoc = std::dynamic_pointer_cast<Model_Document>(aRootDoc);
+ } else {
+ for (int a = aRootDoc->size(ModelAPI_ResultPart::group()) - 1; a >= 0; a--) {
+ ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(
+ aRootDoc->object(ModelAPI_ResultPart::group(), a));
+ if (aPart.get() && aPart->isActivated() && aPart->data()->name() == aDocName) {
+ aDoc = std::dynamic_pointer_cast<Model_Document>(aPart->partDoc());
+ }
+ }
+ }
+ if (aDoc != theDoc) { // so, the first word is the document name => reduce the string for the next manips
+ aSubShapeName = theSubShapeName.substr(aSlash + 1);
+ }
+ }
+
+ std::string aContName = getContextName(aSubShapeName);
if(aContName.empty()) return false;
- ResultPtr aCont = theDoc->findByName(aContName);
+ ResultPtr aCont = aDoc->findByName(aContName);
// possible this is body where postfix is added to distinguish several shapes on the same label
int aSubShapeId = -1; // -1 means sub shape not found
- if (!aCont.get() && aContName == theSubShapeName) {
+ // for result body the name wihtout "_" has higher priority than with it: it is always added
+ if ((!aCont.get()/* || (aCont->groupName() == ModelAPI_ResultBody::group())*/) &&
+ aContName == aSubShapeName) {
size_t aPostIndex = aContName.rfind('_');
if (aPostIndex != std::string::npos) {
std::string aSubContName = aContName.substr(0, aPostIndex);
- aCont = theDoc->findByName(aSubContName);
- if (aCont.get()) {
+ ResultPtr aSubCont = aDoc->findByName(aSubContName);
+ if (aSubCont.get()) {
try {
std::string aNum = aContName.substr(aPostIndex + 1);
aSubShapeId = std::stoi(aNum);
} catch (std::invalid_argument&) {
aSubShapeId = -1;
}
- if (aSubShapeId > 0)
+ if (aSubShapeId > 0) {
aContName = aSubContName;
+ aCont = aSubCont;
+ }
}
}
}
switch (aType)
{
case TopAbs_FACE:
+ case TopAbs_WIRE:
{
- aSelection = findFaceByName(theSubShapeName, theDoc);
+ aSelection = findFaceByName(aSubShapeName, aDoc);
}
break;
case TopAbs_EDGE:
{
- const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName);
+ const TDF_Label& aLabel = aDoc->findNamingName(aSubShapeName);
if(!aLabel.IsNull()) {
Handle(TNaming_NamedShape) aNS;
if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
- aSelection = getShapeFromNS(theSubShapeName, aNS);
+ aSelection = getShapeFromNS(aSubShapeName, aNS);
}
}
}
break;
case TopAbs_VERTEX:
{
- const TDF_Label& aLabel = theDoc->findNamingName(theSubShapeName);
+ const TDF_Label& aLabel = aDoc->findNamingName(aSubShapeName);
if(!aLabel.IsNull()) {
Handle(TNaming_NamedShape) aNS;
if(aLabel.FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
- aSelection = getShapeFromNS(theSubShapeName, aNS);
+ aSelection = getShapeFromNS(aSubShapeName, aNS);
}
}
}
case TopAbs_COMPSOLID:
case TopAbs_SOLID:
case TopAbs_SHELL:
- case TopAbs_WIRE:
default: {//TopAbs_SHAPE
/// case when the whole sketch is selected, so, selection type is compound, but there is no value
if (aCont.get() && aCont->shape().get()) {
return true;
} else if (aSubShapeId > 0) { // try to find sub-shape by the index
TopExp_Explorer anExp(aCont->shape()->impl<TopoDS_Shape>(), aType);
- for(; aSubShapeId > 0 && anExp.More(); aSubShapeId--) {
+ for(; aSubShapeId > 1 && anExp.More(); aSubShapeId--) {
anExp.Next();
}
if (anExp.More()) {
}
// another try to find edge or vertex by faces
std::list<std::string> aListofNames;
- size_t aN = aSelection.IsNull() ? ParseName(theSubShapeName, aListofNames) : 0;
+ size_t aN = aSelection.IsNull() ? ParseName(aSubShapeName, aListofNames) : 0;
if (aSelection.IsNull() && (aType == TopAbs_EDGE || aType == TopAbs_VERTEX)) {
if(aN > 1 && (aN < 4 || (aType == TopAbs_EDGE && aN < 5))) { // 2 || 3 or 4 for EDGE
TopTools_ListOfShape aList;
std::list<std::string>::iterator it = aListofNames.begin();
for(; it != aListofNames.end(); it++){
- const TopoDS_Shape aFace = findFaceByName(*it, theDoc);
+ const TopoDS_Shape aFace = findFaceByName(*it, aDoc);
if(!aFace.IsNull())
aList.Append(aFace);
}
// in case of construction, there is no registered names for all sub-elements,
// even for the main element; so, trying to find them by name (without "&" intersections)
if (aN == 0) {
- size_t aConstrNamePos = theSubShapeName.find("/");
+ size_t aConstrNamePos = aSubShapeName.find("/");
bool isFullName = aConstrNamePos == std::string::npos;
std::string aContrName = aContName;
- // isFullName ? theSubShapeName : theSubShapeName.substr(0, aConstrNamePos);
- ResultPtr aConstr = theDoc->findByName(aContrName);
+ ResultPtr aConstr = aDoc->findByName(aContrName);
if (aConstr.get() && aConstr->groupName() == ModelAPI_ResultConstruction::group()) {
theCont = aConstr;
if (isFullName) {
- theShapeToBeSelected = aConstr->shape();
+ // For the full construction selection shape must be empty.
+ //theShapeToBeSelected = aConstr->shape();
return true;
}
// for sketch sub-elements selected
CompositeFeaturePtr aComposite =
- std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theDoc->feature(aConstr));
+ std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aDoc->feature(aConstr));
if (aComposite.get()) {
if (aType == TopAbs_VERTEX || aType == TopAbs_EDGE) {
// collect all IDs in the name
std::map<int, int> anIDs;
- if (!parseSubIndices(aComposite, theSubShapeName,
+ if (!parseSubIndices(aComposite, aSubShapeName,
aType == TopAbs_EDGE ? "Edge" : "Vertex", anIDs))
return false;
}
}
}
- } else if (aType == TopAbs_FACE) { // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
+ // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
+ } else if (aType == TopAbs_FACE || aType == TopAbs_WIRE) {
+ std::map<int, int> anIDs;
+ if (!parseSubIndices(aComposite, aSubShapeName,
+ aType == TopAbs_FACE ? "Face" : "Wire", anIDs, true))
+ return false;
+
+ NCollection_DataMap<Handle(Geom_Curve), int> allCurves; // curves and orientations of edges
+ const int aSubNum = aComposite->numberOfSubs();
+ for(int a = 0; a < aSubNum; a++) {
+ int aSubID = aComposite->subFeatureId(a);
+ if (anIDs.find(aSubID) != anIDs.end()) {
+ FeaturePtr aSub = aComposite->subFeature(a);
+ const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aSub->results();
+ std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes;
+ for(aRes = aResults.cbegin(); aRes != aResults.cend(); aRes++) {
+ ResultConstructionPtr aConstr =
+ std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(*aRes);
+ if (aConstr->shape() && aConstr->shape()->isEdge()) {
+ const TopoDS_Shape& aResShape = aConstr->shape()->impl<TopoDS_Shape>();
+ TopoDS_Edge anEdge = TopoDS::Edge(aResShape);
+ if (!anEdge.IsNull()) {
+ Standard_Real aFirst, aLast;
+ Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
+ allCurves.Bind(aCurve, anIDs[aSubID] > 0 ? 1 : -1);
+ }
+ }
+ }
+ }
+ }
+ std::shared_ptr<GeomAPI_Shape> aFoundFace = findAppropriateFace(aConstr, allCurves);
+ if (aFoundFace.get()) {
+ if (aType == TopAbs_WIRE) { // just get a wire from face to have wire
+ TopExp_Explorer aWireExp(aFoundFace->impl<TopoDS_Shape>(), TopAbs_WIRE);
+ if (aWireExp.More()) {
+ theShapeToBeSelected.reset(new GeomAPI_Shape);
+ theShapeToBeSelected->setImpl<TopoDS_Shape>(new TopoDS_Shape(aWireExp.Current()));
+ } else return false;
+ } else {
+ theShapeToBeSelected = aFoundFace;
+ }
+ return true;
+ }
+ } else if (aType == TopAbs_WIRE) { // sketch faces is identified by format "Sketch_1/Face-2f-8f-11r"
std::map<int, int> anIDs;
- if (!parseSubIndices(aComposite, theSubShapeName, "Face", anIDs, true))
+ if (!parseSubIndices(aComposite, aSubShapeName, "Wire", anIDs))
return false;
NCollection_DataMap<Handle(Geom_Curve), int> allCurves; // curves and orientations of edges