} else if (theContext->groupName() == ModelAPI_ResultGroup::group()) {
aSelLab.ForgetAllAttributes(true);
TDataStd_UAttribute::Set(aSelLab, kSIMPLE_REF_ID);
- } else { // check the feature context: parent-Part of this feature should not be used
+ } else { // check the feature context: only construction features of PartSet could be selected
FeaturePtr aFeatureContext = std::dynamic_pointer_cast<ModelAPI_Feature>(theContext);
- if (aFeatureContext.get()) {
- if (owner()->document() != aFeatureContext->document()) {
+ if (aFeatureContext.get() && owner()->document() != aFeatureContext->document()) {
+ if (aFeatureContext->results().empty() ||
+ aFeatureContext->firstResult()->groupName() != ModelAPI_ResultConstruction::group()) {
aSelLab.ForgetAllAttributes(true);
myRef.setValue(ObjectPtr());
if (aToUnblock)
std::shared_ptr<GeomAPI_Shape> Model_AttributeSelection::value()
{
- if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
+ if (!myRef.isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
return std::shared_ptr<GeomAPI_Shape>();
CenterType aType = NOT_CENTER;
std::shared_ptr<GeomAPI_Shape> aResult = internalValue(aType);
bool Model_AttributeSelection::isInitialized()
{
- if (ModelAPI_AttributeSelection::isInitialized()) { // additional checks if it is initialized
- std::shared_ptr<GeomAPI_Shape> aResult;
- if (myRef.isInitialized()) {
- TDF_Label aSelLab = selectionLabel();
- // it is just reference to shape, not sub-shape
- if (aSelLab.IsAttribute(kSIMPLE_REF_ID) || aSelLab.IsAttribute(kPART_REF_ID)) {
- ResultPtr aContext = context();
- return aContext.get() != NULL;
- }
- Handle(TNaming_NamedShape) aSelection;
- if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
- return !aSelection->Get().IsNull();
- } else { // for simple construction element: just shape of this construction element
- if (myRef.value().get())
- return true;
- // check that this is on open of document, so, results are not initialized yet
- TDF_Label aRefLab = myRef.myRef->Get();
- if (aRefLab.IsNull() || !owner().get())
- return false;
- std::shared_ptr<Model_Document> aMyDoc =
- std::dynamic_pointer_cast<Model_Document>(owner()->document());
- if (!aMyDoc.get())
- return false;
- // check at least the feature exists
- return aMyDoc->featureByLab(aRefLab).get() != NULL;
- }
+ if (myRef.isInitialized()) {
+ TDF_Label aSelLab = selectionLabel();
+ // it is just reference to shape, not sub-shape
+ if (aSelLab.IsAttribute(kSIMPLE_REF_ID) || aSelLab.IsAttribute(kPART_REF_ID)) {
+ ResultPtr aContext = context();
+ return aContext.get() != NULL;
+ }
+ Handle(TNaming_NamedShape) aSelection;
+ if (selectionLabel().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) {
+ return !aSelection->Get().IsNull();
+ } else { // for simple construction element: just shape of this construction element
+ if (myRef.value().get())
+ return true;
+ // check that this is on open of document, so, results are not initialized yet
+ TDF_Label aRefLab = myRef.myRef->Get();
+ if (aRefLab.IsNull() || !owner().get())
+ return false;
+ std::shared_ptr<Model_Document> aMyDoc =
+ std::dynamic_pointer_cast<Model_Document>(owner()->document());
+ if (!aMyDoc.get())
+ return false;
+ // check at least the feature exists
+ return aMyDoc->featureByLab(aRefLab).get() != NULL;
}
}
return false;
ResultPtr Model_AttributeSelection::context()
{
- if (!ModelAPI_AttributeSelection::isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
+ if (!myRef.isInitialized() && !myTmpContext.get() && !myTmpSubShape.get())
return ResultPtr();
if (myTmpContext.get() || myTmpSubShape.get()) {
TopoDS_Shape aContextShape = aContext->shape()->impl<TopoDS_Shape>();
Selector_Selector aSelector(aSelLab, baseDocumentLab());
aResult = aSelector.restore(aContextShape);
+ bool aWasInvalid = aSelLab.IsAttribute(kINVALID_SELECTION);
setInvalidIfFalse(aSelLab, aResult);
TopoDS_Shape aNewShape;
if (aSelLab.FindAttribute(TNaming_NamedShape::GetID(), aNS))
aNewShape = aNS->Get();
- if (anOldShape.IsNull() || aNewShape.IsNull() || !anOldShape.IsEqual(aNewShape)) {
+ if (anOldShape.IsNull() || aNewShape.IsNull() || !anOldShape.IsEqual(aNewShape) || aWasInvalid)
+ {
// shape type should not be changed: if shape becomes compound of such shapes, then split
if (myParent && !anOldShape.IsNull() && !aNewShape.IsNull() &&
anOldShape.ShapeType() != aNewShape.ShapeType() &&
aNewShape.ShapeType() == TopAbs_COMPOUND) {
split(aContext, aNewShape, anOldShape.ShapeType());
}
+ // for issue #3076 check that the new value belongs to the new context
+ if (!aNewShape.IsNull() && !aContextShape.IsNull() &&
+ (aNewShape.ShapeType() == TopAbs_VERTEX || aNewShape.ShapeType() == TopAbs_EDGE ||
+ aNewShape.ShapeType() == TopAbs_FACE)) {
+ TopExp_Explorer anExp(aContextShape, aNewShape.ShapeType());
+ for(; anExp.More(); anExp.Next()) {
+ if (anExp.Current().IsSame(aNewShape))
+ break;
+ }
+ aResult = setInvalidIfFalse(aSelLab, anExp.More());
+ }
owner()->data()->sendAttributeUpdated(this); // send updated if shape is changed
}
return aResult;
CenterType aCenterType = NOT_CENTER;
std::shared_ptr<GeomAPI_Shape> aSubSh = internalValue(aCenterType);
- ResultPtr aCont = context();
- if (!aCont.get() ||
- (aCont->groupName() == ModelAPI_ResultConstruction::group() && contextFeature().get())) {
+ FeaturePtr aContFeature = contextFeature();
+ if (aContFeature.get()) {
+ std::string aResName;
+ // checking part-owner
+ if (aContFeature->document() != owner()->document())
+ aResName += aContFeature->document()->kind() + "/";
// selection of a full feature
- FeaturePtr aFeatureCont = contextFeature();
- if (aFeatureCont.get()) {
- return kWHOLE_FEATURE + aFeatureCont->name();
+ if (aContFeature.get()) {
+ return aResName + kWHOLE_FEATURE + aContFeature->name();
}
// in case of selection of removed result
return "";
}
+ ResultPtr aCont = context();
TDF_Label aSelLab = selectionLabel();
if (aSelLab.IsAttribute(kSIMPLE_REF_ID)) { // whole context, no value
return contextName(aCont);
void Model_AttributeSelection::concealedFeature(
- const FeaturePtr theFeature, const FeaturePtr theStop, std::list<FeaturePtr>& theConcealers)
+ const FeaturePtr theFeature, const FeaturePtr theStop, const bool theCheckCopy,
+ std::list<FeaturePtr>& theConcealers, const ResultPtr theResultOfFeature)
{
std::set<FeaturePtr> alreadyProcessed;
alreadyProcessed.insert(theFeature);
if (theStop.get())
alreadyProcessed.insert(theStop);
/// iterate all results to find the concealment-attribute
- const std::list<ResultPtr>& aRootRes = theFeature->results();
+ std::list<ResultPtr> aRootRes;
+ if (theResultOfFeature.get()) {
+ ResultPtr aRoot = ModelAPI_Tools::bodyOwner(theResultOfFeature, true);
+ aRootRes.push_back(aRoot ? aRoot : theResultOfFeature);
+ } else { // all results of a feature
+ aRootRes = theFeature->results();
+ }
std::list<ResultPtr>::const_iterator aRootIter = aRootRes.cbegin();
for(; aRootIter != aRootRes.cend(); aRootIter++) {
std::list<ResultPtr> allRes;
if (alreadyProcessed.find(aRefFeat) != alreadyProcessed.end()) // optimization
continue;
alreadyProcessed.insert(aRefFeat);
- if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id()))
+ if (ModelAPI_Session::get()->validators()->isConcealed(aRefFeat->getKind(), (*aRef)->id())
+ || (theCheckCopy &&
+ std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(aRefFeat).get()))
{
// for extrusion cut in python script the nested sketch reference may be concealed before
// it is nested, so, check this composite feature is valid
} else aResIter++;
}
+ bool aStaySame = false;
if (aResults.empty()) {
// check the context become concealed by operation which is earlier than this selection
FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
FeaturePtr aContextOwner = theDoc->feature(theContext);
std::list<FeaturePtr> aConcealers;
- concealedFeature(aContextOwner, aThisFeature, aConcealers);
+ concealedFeature(aContextOwner, aThisFeature, false, aConcealers, theContext);
std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
for(; aConcealer != aConcealers.end(); aConcealer++) {
std::list<ResultPtr> aRefResults;
if (aResults.empty())
return true; // feature conceals result, return true, so the context will be removed
}
- if (aResults.empty())
- return false; // no modifications found, must stay the same
+ aStaySame = aResults.empty();
+ }
+ if (myParent && myParent->isMakeCopy()) {
+ // check there are copies before the new results, so, make a copy
+ std::set<ResultPtr>::iterator aResIter = aResults.begin();
+ std::list<ObjectPtr> aCopyContext;
+ std::list<GeomShapePtr> aCopyVals;
+ // features between the new and the old: check the "Move" interface to get a copy
+ FeaturePtr aRootOwner = theDoc->feature(theContext);
+ FeaturePtr anOwner = ModelAPI_Tools::compositeOwner(aRootOwner);
+ for(; anOwner.get(); anOwner = ModelAPI_Tools::compositeOwner(anOwner))
+ aRootOwner = anOwner;
+ FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
+ // iterate all results to find a "Copy" features between the new and one and to add the
+ // copy-results also to results if this attribute refers to the copied shape
+ int anIndex = kUNDEFINED_FEATURE_INDEX;
+ for(FeaturePtr aFeat = theDoc->objects()->nextFeature(aRootOwner, anIndex); aFeat.get() &&
+ aFeat != aThisFeature; aFeat = theDoc->objects()->nextFeature(aFeat, anIndex)) {
+ std::shared_ptr<ModelAPI_FeatureCopyInterface> aCopier =
+ std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(aFeat);
+ if (aCopier.get()) {
+ GeomShapePtr aValShape(new GeomAPI_Shape);
+ aValShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(
+ theValShape.IsNull() ? theContShape : theValShape));
+ aCopier->getCopies(theContext, aValShape, aCopyContext, aCopyVals);
+ }
+ }
+ // check for the further modifications of the copy contexts and values
+ std::list<ObjectPtr>::iterator aCopyContIter = aCopyContext.begin();
+ std::list<GeomShapePtr>::iterator aCopyValIter = aCopyVals.begin();
+ for(; aCopyContIter != aCopyContext.end(); aCopyContIter++, aCopyValIter++) {
+ ResultPtr aNewCont = std::dynamic_pointer_cast<ModelAPI_Result>(*aCopyContIter);
+ TopoDS_Shape aNewContShape = aNewCont->shape()->impl<TopoDS_Shape>();
+ GeomShapePtr aNewVal = *aCopyValIter;
+ TopoDS_Shape aNewValShape;
+ if (aNewVal.get() && !aNewVal->isNull())
+ aNewValShape = aNewVal->impl<TopoDS_Shape>();
+ std::list<ResultPtr> aNewRes;
+ TopTools_ListOfShape aNewUpdatedVal;
+ if (searchNewContext(theDoc, aNewContShape, aNewCont, aNewValShape,
+ theAccessLabel, aNewRes, aNewUpdatedVal)) {
+ // append new results instead of the current ones
+ std::list<ResultPtr>::iterator aNewIter = aNewRes.begin();
+ TopTools_ListIteratorOfListOfShape aNewUpdVal(aNewUpdatedVal);
+ for(; aNewIter != aNewRes.end(); aNewIter++, aNewUpdVal.Next()) {
+ theResults.push_back(*aNewIter);
+ theValShapes.Append(aNewUpdVal.Value());
+ }
+ } else { // the current result is good
+ theResults.push_back(aNewCont);
+ theValShapes.Append(aNewValShape);
+ }
+ }
+ if (aStaySame && !theResults.empty()) { // no changes except copy, so, keep the origin as first
+ theResults.push_front(theContext);
+ theValShapes.Prepend(theValShape);
+ return true;
+ }
}
+ if (aStaySame)
+ return false;
+
// iterate all results to find further modifications
std::set<ResultPtr>::iterator aResIter = aResults.begin();
- for(; aResIter != aResults.end(); aResIter++) {
+ for(aResIter = aResults.begin(); aResIter != aResults.end(); aResIter++) {
if (aResIter->get() != NULL) {
+ ResultPtr aNewResObj = *aResIter;
// compute new values by two contexts: the old and the new
TopTools_ListOfShape aValShapes;
- computeValues(theContext, *aResIter, theValShape, aValShapes);
+ computeValues(theContext, aNewResObj, theValShape, aValShapes);
TopTools_ListIteratorOfListOfShape aNewVal(aValShapes);
for(; aNewVal.More(); aNewVal.Next()) {
std::list<ResultPtr> aNewRes;
TopTools_ListOfShape aNewUpdatedVal;
TopoDS_Shape aNewValSh = aNewVal.Value();
- TopoDS_Shape aNewContShape = (*aResIter)->shape()->impl<TopoDS_Shape>();
+ TopoDS_Shape aNewContShape = aNewResObj->shape()->impl<TopoDS_Shape>();
+
if (theValShape.IsNull() && aNewContShape.IsSame(aNewValSh))
aNewValSh.Nullify();
- if (searchNewContext(theDoc, aNewContShape, *aResIter, aNewValSh,
+ if (searchNewContext(theDoc, aNewContShape, aNewResObj, aNewValSh,
theAccessLabel, aNewRes, aNewUpdatedVal))
{
// append new results instead of the current ones
theValShapes.Append(aNewUpdVal.Value());
}
} else { // the current result is good
- theResults.push_back(*aResIter);
+ theResults.push_back(aNewResObj);
theValShapes.Append(aNewValSh);
}
}
if (aFeature.get()) {
FeaturePtr aThisFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(owner());
std::list<FeaturePtr> aConcealers;
- concealedFeature(aFeature, aThisFeature, aConcealers);
+ bool aCopyPossible = myParent && myParent->isMakeCopy();
+ concealedFeature(aFeature, aThisFeature, aCopyPossible, aConcealers, ResultPtr());
if (aConcealers.empty())
return;
+ // if there are copies, but no direct modification, keep the original
+ bool aKeepOrigin = false;
+ if (aCopyPossible) {
+ std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
+ for(aKeepOrigin = true; aConcealer != aConcealers.end(); aConcealer++)
+ if (!std::dynamic_pointer_cast<ModelAPI_FeatureCopyInterface>(*aConcealer).get()) {
+ aKeepOrigin = false;
+ break;
+ }
+ if (aKeepOrigin) {
+ aConcealers.push_front(aFeature);
+ }
+ }
bool aChanged = false;
std::list<FeaturePtr>::iterator aConcealer = aConcealers.begin();
for(; aConcealer != aConcealers.end(); aConcealer++)
- if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates
- setValue(*aConcealer, anEmptyShape);
- aChanged = true;
- }
- if (aConcealer == aConcealers.end()) {
- if (!aChanged) // remove this
- theRemove = true;
- } else { // append new
- for(aConcealer++; aConcealer != aConcealers.end(); aConcealer++)
- if (!myParent->isInList(*aConcealer, anEmptyShape)) // avoid addition of duplicates
+ if (aChanged) {
+ if (aKeepOrigin || !myParent->isInList(*aConcealer, anEmptyShape))
myParent->append(*aConcealer, anEmptyShape);
- }
- if (aChanged) // searching for the further modifications
+ } else {
+ if (!myParent->isInList(*aConcealer, anEmptyShape)) {// avoid addition of duplicates
+ setValue(*aConcealer, anEmptyShape);
+ aChanged = true;
+ } else if (aCopyPossible && *aConcealer == aFeature) {// keep origin in case of copy
+ aChanged = true;
+ }
+ }
+ if (!aChanged) // remove this
+ theRemove = true;
+ else if (!aKeepOrigin) // searching further modifications only if current changed
updateInHistory(theRemove);
}
}
aListShapeType = GeomAPI_Shape::FACE;
}
+ // issue #3031: skip topology if there is more convenient shape type presents in the
+ // same context as a result of this
+ bool isWholeResult = myParent && myParent->isWholeResultAllowed() && !aSubShape.get();
+ GeomAPI_Shape::ShapeType allowedType = GeomAPI_Shape::SHAPE;
+ if (isWholeResult) {
+ std::list<ResultPtr>::iterator aNewCont = aNewContexts.begin();
+ TopTools_ListIteratorOfListOfShape aNewValues(aValShapes);
+ for(; aNewCont != aNewContexts.end(); aNewCont++, aNewValues.Next()) {
+ if (aNewValues.Value().IsNull()) { // only for the whole context
+ GeomAPI_Shape::ShapeType aShapeType = (*aNewCont)->shape()->shapeType();
+ if (allowedType == GeomAPI_Shape::SHAPE) { // just set this one
+ allowedType = aShapeType;
+ } else {
+ GeomAPI_Shape::ShapeType anAllowed = allowedType;
+ if (anAllowed != aShapeType) { // select the best, nearest to the origin
+ GeomAPI_Shape::ShapeType anOldShapeType = aContext->shape()->shapeType();
+ GeomAPI_Shape::ShapeType aDeltaAllowed =
+ (GeomAPI_Shape::ShapeType)(anOldShapeType - anAllowed);
+ if (aDeltaAllowed < 0)
+ aDeltaAllowed = (GeomAPI_Shape::ShapeType)(-aDeltaAllowed);
+ GeomAPI_Shape::ShapeType aDeltaThis =
+ (GeomAPI_Shape::ShapeType)(anOldShapeType - aShapeType);
+ if (aDeltaThis < 0)
+ aDeltaThis = (GeomAPI_Shape::ShapeType)(-aDeltaThis);
+ if (aDeltaThis == aDeltaAllowed) { // equal distance to context, select complicated
+ if (anOldShapeType < anAllowed)
+ allowedType = aShapeType;
+ } else if (aDeltaAllowed > aDeltaThis) { // this wins
+ allowedType = aShapeType;
+ }
+ }
+ }
+ }
+ }
+ }
+
std::list<ResultPtr>::iterator aNewCont = aNewContexts.begin();
TopTools_ListIteratorOfListOfShape aNewValues(aValShapes);
bool aFirst = true; // first is set to this, next are appended to parent
if (aSkippedContext.count(*aNewCont))
continue;
+ if (isWholeResult && aNewValues.Value().IsNull())
+ if (allowedType != GeomAPI_Shape::SHAPE &&
+ (*aNewCont)->shape()->shapeType() != allowedType)
+ continue; // there is better result exists with the better shape type (issue #3031)
+
GeomShapePtr aValueShape;
if (!aNewValues.Value().IsNull()) {
aValueShape = std::make_shared<GeomAPI_Shape>();
}
if (aListShapeType != GeomAPI_Shape::SHAPE && aListShapeType != aShapeShapeType) {
// exception is for whole results selected
- if (!myParent || !myParent->isWholeResultAllowed() || aSubShape.get()) {
+ if (!isWholeResult) {
continue;
}
}
if (!myParent || !myParent->isInList(aNewContext, aValueShape)) { // avoid duplicates
setValue(aNewContext, aValueShape);
aFirst = false;
+ } else if (aNewContext == aContext && myParent && myParent->isMakeCopy()) {
+ // this may be exactly the old one, not modified in case of copy
+ aFirst = false;
}
} else if (myParent) {
if (!myParent->isInList(aNewContext, aValueShape)) // avoid addition of duplicates
static TDF_Label anEmpty;
return anEmpty;
}
+
+void Model_AttributeSelection::reset()
+{
+ ModelAPI_AttributeSelection::reset();
+ myRef.reset();
+}