#include <ModelAPI_ResultConstruction.h>
#include <ModelAPI_ResultPart.h>
#include <ModelAPI_CompositeFeature.h>
+#include <ModelAPI_Tools.h>
#include <GeomAPI_Shape.h>
#include <GeomAPI_PlanarEdges.h>
#include <Events_Error.h>
#include <TopAbs_ShapeEnum.hxx>
#include <TopoDS_Iterator.hxx>
#include <TNaming_Iterator.hxx>
+#include <BRep_Builder.hxx>
using namespace std;
//#define DEB_NAMING 1
#ifdef DEB_NAMING
#include <BRepTools.hxx>
#endif
-/// adeed to the index in the packed map to signalize that the vertex of edge is seleted
+/// 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;
// identifier that there is simple reference: selection equals to context
Standard_GUID kCONSTUCTION_SIMPLE_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb28");
// reference to Part sub-object
Standard_GUID kPART_REF_ID("635eacb2-a1d6-4dec-8348-471fae17cb27");
+// selection is invalid after recomputation
+Standard_GUID kINVALID_SELECTION("bce47fd7-80fa-4462-9d63-2f58acddd49d");
// on this label is stored:
// TNaming_NamedShape - selected shape
TDF_Label aSelLab = selectionLabel();
aSelLab.ForgetAttribute(kSIMPLE_REF_ID);
aSelLab.ForgetAttribute(kCONSTUCTION_SIMPLE_REF_ID);
+ aSelLab.ForgetAttribute(kINVALID_SELECTION);
bool isDegeneratedEdge = false;
// do not use the degenerated edge as a shape, a null context and shape is used in the case
if (theContext->groupName() == ModelAPI_ResultBody::group()) {
// do not select the whole shape for body:it is already must be in the data framework
// equal and null selected objects mean the same: object is equal to context,
- // TODO: synchronize with GUI later that it must be null always
if (theContext->shape().get() &&
(theContext->shape()->isEqual(theSubShape) || !theSubShape.get())) {
aSelLab.ForgetAllAttributes(true);
// to sub, so the whole result is selected
aSelLab.ForgetAllAttributes(true);
TDataStd_UAttribute::Set(aSelLab, kCONSTUCTION_SIMPLE_REF_ID);
+ ResultConstructionPtr aConstruction =
+ std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(theContext);
+ if (aConstruction->isInfinite()) {
+ // For correct naming selection, put the shape into the naming structure.
+ // It seems sub-shapes are not needed: only this shape is (and can be ) selected.
+ TNaming_Builder aBuilder(aSelLab);
+ aBuilder.Generated(theContext->shape()->impl<TopoDS_Shape>());
+ std::shared_ptr<Model_Document> aMyDoc =
+ std::dynamic_pointer_cast<Model_Document>(owner()->document());
+ std::string aName = theContext->data()->name();
+ aMyDoc->addNamingName(aSelLab, aName);
+ TDataStd_Name::Set(aSelLab, aName.c_str());
+ } else { // for sketch the naming is needed in DS
+ BRep_Builder aCompoundBuilder;
+ TopoDS_Compound aComp;
+ aCompoundBuilder.MakeCompound(aComp);
+ for(int a = 0; a < aConstruction->facesNum(); a++) {
+ TopoDS_Shape aFace = aConstruction->face(a)->impl<TopoDS_Shape>();
+ aCompoundBuilder.Add(aComp, aFace);
+ }
+ std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape);
+ aShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aComp));
+ selectConstruction(theContext, aShape);
+ }
} else {
selectConstruction(theContext, theSubShape);
}
}
std::shared_ptr<GeomAPI_Shape> aResult;
+ TDF_Label aSelLab = selectionLabel();
+ if (aSelLab.IsAttribute(kINVALID_SELECTION))
+ return aResult;
+
if (myRef.isInitialized()) {
- TDF_Label aSelLab = selectionLabel();
if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape
ResultPtr aContext = context();
if (!aContext.get())
return aResult; // empty result
}
if (aSelLab.IsAttribute(kPART_REF_ID)) {
- /* TODO: implement used text here
ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(context());
if (!aPart.get() || !aPart->isActivated())
return std::shared_ptr<GeomAPI_Shape>(); // postponed naming needed
if (selectionLabel().FindAttribute(TDataStd_Integer::GetID(), anIndex)) {
return aPart->selectionValue(anIndex->Get());
}
+ /*
Handle(TDataStd_Name) aName;
if (!selectionLabel().FindAttribute(TDataStd_Name::GetID(), aName)) {
return std::shared_ptr<GeomAPI_Shape>(); // something is wrong
}
- return aPart->shapeInPart(TCollection_AsciiString(aName).ToCString());
+ return aPart->shapeInPart(TCollection_AsciiString(aName->Get()).ToCString());
*/
}
return aResult;
}
+bool Model_AttributeSelection::isInvalid()
+{
+ return selectionLabel().IsAttribute(kINVALID_SELECTION) == Standard_True;
+}
+
bool Model_AttributeSelection::isInitialized()
{
- if (ModelAPI_AttributeSelection::isInitialized()) { // additional checkings if it is initialized
+ if (ModelAPI_AttributeSelection::isInitialized()) { // additional checks if it is initialized
std::shared_ptr<GeomAPI_Shape> aResult;
if (myRef.isInitialized()) {
TDF_Label aSelLab = selectionLabel();
TDF_LabelMap& Model_AttributeSelection::scope()
{
if (myScope.IsEmpty()) { // create a new scope if not yet done
- // gets all featueres with named shapes that are bofore this feature label (before in history)
+ // gets all features with named shapes that are before this feature label (before in history)
DocumentPtr aMyDoc = owner()->document();
std::list<std::shared_ptr<ModelAPI_Feature> > allFeatures = aMyDoc->allFeatures();
std::list<std::shared_ptr<ModelAPI_Feature> >::iterator aFIter = allFeatures.begin();
+ bool aMePassed = false;
+ CompositeFeaturePtr aComposite =
+ std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(owner());
+ FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+ CompositeFeaturePtr aCompositeOwner, aCompositeOwnerOwner;
+ if (aFeature.get()) {
+ aCompositeOwner = ModelAPI_Tools::compositeOwner(aFeature);
+ if (aCompositeOwner.get()) {
+ aCompositeOwnerOwner = ModelAPI_Tools::compositeOwner(aCompositeOwner);
+ }
+ }
for(; aFIter != allFeatures.end(); aFIter++) {
- if (*aFIter == owner()) break; // the left features are created later
- if (aFIter->get() && (*aFIter)->data()->isValid()) {
+ if (*aFIter == owner()) { // the left features are created later (except subs of composite)
+ aMePassed = true;
+ continue;
+ }
+ bool isInScope = !aMePassed;
+ if (!isInScope && aComposite.get()) { // try to add sub-elements of composite if this is composite
+ if (aComposite->isSub(*aFIter))
+ isInScope = true;
+ }
+ // remove the composite-owner of this feature (sketch in extrusion-cut)
+ if (isInScope && (aCompositeOwner == *aFIter || aCompositeOwnerOwner == *aFIter))
+ isInScope = false;
+
+ if (isInScope && aFIter->get() && (*aFIter)->data()->isValid()) {
TDF_Label aFeatureLab = std::dynamic_pointer_cast<Model_Data>(
(*aFIter)->data())->label().Father();
TDF_ChildIDIterator aNSIter(aFeatureLab, TNaming_NamedShape::GetID(), 1);
return 0; // unknown
}
+/// Sets the invalid flag if flag is false, or removes it if "true"
+/// Returns theFlag
+static bool setInvalidIfFalse(TDF_Label& theLab, const bool theFlag) {
+ if (theFlag) {
+ theLab.ForgetAttribute(kINVALID_SELECTION);
+ } else {
+ TDataStd_UAttribute::Set(theLab, kINVALID_SELECTION);
+ }
+ return theFlag;
+}
+
bool Model_AttributeSelection::update()
{
- ResultPtr aContext = context();
- if (!aContext.get()) return false;
TDF_Label aSelLab = selectionLabel();
+ ResultPtr aContext = context();
+ if (!aContext.get())
+ return setInvalidIfFalse(aSelLab, false);
if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // it is just reference to shape, not sub-shape
- return aContext->shape() && !aContext->shape()->isNull();
+ return setInvalidIfFalse(aSelLab, aContext->shape() && !aContext->shape()->isNull());
}
if (aSelLab.IsAttribute(kCONSTUCTION_SIMPLE_REF_ID)) { // it is just reference to construction, not sub-shape
- return aContext->shape() && !aContext->shape()->isNull();
+ // if there is a sketch, the sketch-naming must be updated
+ ResultConstructionPtr aConstruction =
+ std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
+ if (!aConstruction->isInfinite()) {
+ BRep_Builder aCompoundBuilder;
+ TopoDS_Compound aComp;
+ aCompoundBuilder.MakeCompound(aComp);
+ for(int a = 0; a < aConstruction->facesNum(); a++) {
+ TopoDS_Shape aFace = aConstruction->face(a)->impl<TopoDS_Shape>();
+ aCompoundBuilder.Add(aComp, aFace);
+ }
+ std::shared_ptr<GeomAPI_Shape> aShape(new GeomAPI_Shape);
+ aShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aComp));
+ selectConstruction(aContext, aShape);
+ }
+ return setInvalidIfFalse(aSelLab, aContext->shape() && !aContext->shape()->isNull());
}
if (aSelLab.IsAttribute(kPART_REF_ID)) { // it is reference to the part object
std::shared_ptr<GeomAPI_Shape> aNoSelection;
- return selectPart(aContext, aNoSelection, true);
+ return setInvalidIfFalse(aSelLab, selectPart(aContext, aNoSelection, true));
}
if (aContext->groupName() == ModelAPI_ResultBody::group()) {
TNaming_Selector aSelector(aSelLab);
bool aResult = aSelector.Solve(scope()) == Standard_True;
owner()->data()->sendAttributeUpdated(this);
- return aResult;
+ return setInvalidIfFalse(aSelLab, aResult);
} 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
// getting a type of selected shape
Handle(TDataStd_Integer) aTypeAttr;
if (!aLab.FindAttribute(TDataStd_Integer::GetID(), aTypeAttr)) {
- return false;
+ return setInvalidIfFalse(aSelLab, false);
}
TopAbs_ShapeEnum aShapeType = (TopAbs_ShapeEnum)(aTypeAttr->Get());
// selected indexes will be needed in each "if"
CompositeFeaturePtr aComposite =
std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aContextFeature);
if (!aComposite.get() || aComposite->numberOfSubs() == 0) {
- return false;
+ return setInvalidIfFalse(aSelLab, false);
}
if (aShapeType == TopAbs_FACE) { // compound is for the whole sketch selection
// If this is a wire with plane defined thin it is a sketch-like object
if (!aConstructionContext->facesNum()) // no faces, update can not work correctly
- return false;
+ return setInvalidIfFalse(aSelLab, false);
// if there is no edges indexes, any face can be used: take the first
std::shared_ptr<GeomAPI_Shape> aNewSelected;
if (aNoIndexes) {
aNewSelected = aConstructionContext->face(0);
} else { // searching for most looks-like initial face by the indexes
- // prepare edges of the current resut for the fast searching
+ // prepare edges of the current result for the fast searching
NCollection_DataMap<Handle(Geom_Curve), int> allCurves; // curves and orientations of edges
const int aSubNum = aComposite->numberOfSubs();
for(int a = 0; a < aSubNum; a++) {
}
}
}
- double aBestFound = 0; // best percentage of found edges
+ int aBestFound = 0; // best number of found edges (not percentage: issue 1019)
int aBestOrient = 0; // for the equal "BestFound" additional parameter is orientation
for(int aFaceIndex = 0; aFaceIndex < aConstructionContext->facesNum(); aFaceIndex++) {
int aFound = 0, aNotFound = 0, aSameOrientation = 0;
}
}
if (aFound + aNotFound != 0) {
- double aSum = aFound + aNotFound;
- // aSameOrientation: if edges are same, take where orientation is better
- double aPercentage = double(aFound) / double(aFound + aNotFound);
- if (aPercentage > aBestFound ||
- (aPercentage == aBestFound && aSameOrientation > aBestOrient)) {
- aBestFound = aPercentage;
+ if (aFound > aBestFound ||
+ (aFound == aBestFound && aSameOrientation > aBestOrient)) {
+ aBestFound = aFound;
aBestOrient = aSameOrientation;
aNewSelected = aConstructionContext->face(aFaceIndex);
}
if (aNewSelected) { // store this new selection
selectConstruction(aContext, aNewSelected);
owner()->data()->sendAttributeUpdated(this);
- return true;
+ return setInvalidIfFalse(aSelLab, true);
+ } else { // if the selection is not found, put the empty shape: it's better to have disappeared shape, than the old, the lost one
+ TNaming_Builder anEmptyBuilder(selectionLabel());
+ return setInvalidIfFalse(aSelLab, false);
}
} else if (aShapeType == TopAbs_EDGE) {
// just reselect the edge by the id
if (aRes && aRes->shape() && aRes->shape()->isEdge()) { // found!
selectConstruction(aContext, aRes->shape());
owner()->data()->sendAttributeUpdated(this);
- return true;
+ return setInvalidIfFalse(aSelLab, true);
}
}
}
if (aRes->shape()->isVertex() && aVertexNum == 0) { // found!
selectConstruction(aContext, aRes->shape());
owner()->data()->sendAttributeUpdated(this);
- return true;
+ return setInvalidIfFalse(aSelLab, true);
} else if (aRes->shape()->isEdge() && aVertexNum > 0) {
const TopoDS_Shape& anEdge = aRes->shape()->impl<TopoDS_Shape>();
int aVIndex = 1;
aVertex->setImpl(new TopoDS_Shape(aVExp.Current()));
selectConstruction(aContext, aVertex);
owner()->data()->sendAttributeUpdated(this);
- return true;
+ return setInvalidIfFalse(aSelLab, true);
}
aVIndex++;
}
} else { // simple construction element: the selected is that needed
selectConstruction(aContext, aContext->shape());
owner()->data()->sendAttributeUpdated(this);
- return true;
+ return setInvalidIfFalse(aSelLab, true);
}
}
- return false; // unknown case
+ return setInvalidIfFalse(aSelLab, false); // unknown case
}
}
TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl<TopoDS_Shape>() : aContext;
/// fix for issue 411: result modified shapes must not participate in this selection mechanism
- /*
FeaturePtr aFeatureOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
if (aFeatureOwner.get())
aFeatureOwner->eraseResults();
- */
if (!aContext.IsNull()) {
aSel.Select(aNewShape, aContext);
}
aName<<"f";
else if (theOrientation == -1)
aName<<"r";
- } else { // make a compisite name from all sub-elements indexes: "1_2_3_4"
+ } else { // make a composite name from all sub-elements indexes: "1_2_3_4"
TColStd_MapIteratorOfPackedMapOfInteger aRef(theRefs->GetMap());
for(; aRef.More(); aRef.Next()) {
aName<<"-"<<aRef.Key();
}
std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(owner()->data());
TDF_Label aLab = myRef.myRef->Label();
- // identify the reuslts of sub-object of the composite by edges
+ // identify the results of sub-object of the composite by edges
// save type of the selected shape in integer attribute
TopAbs_ShapeEnum aShapeType = aSubShape.ShapeType();
TDataStd_Integer::Set(aLab, (int)aShapeType);
if (allCurves.Contains(aCurve)) {
int anID = aComposite->subFeatureId(a);
aRefs->Add(anID);
- if (aShapeType != TopAbs_EDGE) { // face nneds the sub-edges on sub-labels
+ if (aShapeType != TopAbs_EDGE) { // face needs the sub-edges on sub-labels
// add edges to sub-label to support naming for edges selection
TopExp_Explorer anEdgeExp(aSubShape, TopAbs_EDGE);
for(; anEdgeExp.More(); anEdgeExp.Next()) {
}
return true; // nothing to do, referencing just by name
}
- // store the shape (in case part is not loaded it should be usefull
+ // store the shape (in case part is not loaded it should be useful
TopoDS_Shape aShape;
std::string aName = theContext->data()->name();
- if (theSubShape->isNull()) {// the whole part shape is selected
+ if (!theSubShape.get() || theSubShape->isNull()) {// the whole part shape is selected
aShape = theContext->shape()->impl<TopoDS_Shape>();
} else {
aShape = theSubShape->impl<TopoDS_Shape>();
{
if(theSubShapeName.empty() || theType.empty()) return;
+ // check this is Part-name: 2 delimiters in the name
+ std::size_t aPartEnd = theSubShapeName.find('/');
+ if (aPartEnd != string::npos && aPartEnd != theSubShapeName.rfind('/')) {
+ std::string aPartName = theSubShapeName.substr(0, aPartEnd);
+ ObjectPtr aFound = owner()->document()->objectByName(ModelAPI_ResultPart::group(), aPartName);
+ if (aFound.get()) { // found such part, so asking it for the name
+ ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(aFound);
+ string aNameInPart = theSubShapeName.substr(aPartEnd + 1);
+ int anIndex;
+ std::shared_ptr<GeomAPI_Shape> aSelected = aPart->shapeInPart(aNameInPart, theType, anIndex);
+ if (aSelected.get()) {
+ setValue(aPart, aSelected);
+ TDataStd_Integer::Set(selectionLabel(), anIndex);
+ return;
+ }
+ }
+ }
+
Model_SelectionNaming aSelNaming(selectionLabel());
std::shared_ptr<Model_Document> aDoc =
std::dynamic_pointer_cast<Model_Document>(owner()->document());