.. centered::\r
Construction pop-up menu\r
\r
-The order of features can be changed using *Move to the end* pop-up menu command. The selected feature will be moved to the end of feature list.\r
+The order of features can be changed using *Move to the end* pop-up menu command. It works only for Group features. The selected group will be moved to the end of features list.\r
\r
Folders can be used to arrange long Tree View for features.\r
\r
AttributeSelectionListPtr anAttrList = aBase->selectionList(CollectionPlugin_Group::LIST_ID());
- theDumper << aBase << " = model.addGroup(" << aDocName << ", " << anAttrList << ")" << std::endl;
+ theDumper << aBase << " = model.addGroup(" << aDocName << ", " << anAttrList;
+ if (anAttrList->isGeometricalSelection())
+ theDumper <<", True";
+ theDumper << ")" << std::endl;
}
//==================================================================================================
GroupPtr addGroup(const std::shared_ptr<ModelAPI_Document>& thePart,
- const std::list<ModelHighAPI_Selection>& theGroupList)
+ const std::list<ModelHighAPI_Selection>& theGroupList,
+ const bool theShareSameTopology)
{
std::shared_ptr<ModelAPI_Feature> aFeature = thePart->addFeature(CollectionAPI_Group::ID());
+ if (theShareSameTopology)
+ aFeature->selectionList(CollectionPlugin_Group::LIST_ID())->setGeometricalSelection(true);
return GroupPtr(new CollectionAPI_Group(aFeature, theGroupList));
}
/// \brief Create Group feature.
COLLECTIONAPI_EXPORT
GroupPtr addGroup(const std::shared_ptr<ModelAPI_Document>& thePart,
- const std::list<ModelHighAPI_Selection>& theGroupList);
+ const std::list<ModelHighAPI_Selection>& theGroupList,
+ const bool theShareSameTopology = false);
#endif // CollectionAPI_Group_H_
aResult = theCurrent;
return aResult;
}
+
+void Model_AttributeSelection::combineGeometrical()
+{
+ if (myTmpContext.get() || myTmpSubShape.get())
+ return;
+ TDF_Label aSelLab = selectionLabel();
+ if (aSelLab.IsAttribute(kINVALID_SELECTION) || !myRef.isInitialized())
+ return;
+
+ if (aSelLab.IsAttribute(kCIRCLE_CENTER) || aSelLab.IsAttribute(kELLIPSE_CENTER1) ||
+ aSelLab.IsAttribute(kELLIPSE_CENTER2) || aSelLab.IsAttribute(kSIMPLE_REF_ID))
+ return;
+
+ if (aSelLab.IsAttribute(kPART_REF_ID)) {
+ ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(context());
+ if (!aPart.get() || !aPart->isActivated())
+ return; // postponed naming needed
+ Handle(TDataStd_Integer) anIndex;
+ if (aSelLab.FindAttribute(TDataStd_Integer::GetID(), anIndex)) {
+ if (anIndex->Get()) { // special selection attribute was created, use it
+ std::string aNewName;
+ aPart->combineGeometrical(anIndex->Get(), aNewName);
+ TDataStd_Name::Set(aSelLab, aNewName.c_str());
+ }
+ }
+ return;
+ }
+
+ std::shared_ptr<Model_ResultConstruction> aConstr =
+ std::dynamic_pointer_cast<Model_ResultConstruction>(context());
+ if (aConstr.get())
+ return;
+ FeaturePtr aFeature = contextFeature();
+ if (aFeature.get())
+ return;
+
+ Selector_Selector aSelector(aSelLab);
+ if (ModelAPI_Session::get()->moduleDocument() != owner()->document()) {
+ aSelector.setBaseDocument(std::dynamic_pointer_cast<Model_Document>
+ (ModelAPI_Session::get()->moduleDocument())->extConstructionsLabel());
+ }
+ if (aSelector.restore()) {
+ TopoDS_Shape aContextShape = context()->shape()->impl<TopoDS_Shape>();
+ aSelector.combineGeometrical(aContextShape);
+ }
+}
/// Returns the name by context. Adds the part name if the context is located in other document
MODEL_EXPORT virtual std::string contextName(const ResultPtr& theContext) const;
+ /// Makes the current local selection becomes all sub-shapes with same base geometry.
+ MODEL_EXPORT virtual void combineGeometrical();
+
protected:
/// Objects are created for features automatically
MODEL_EXPORT Model_AttributeSelection(TDF_Label& theLabel);
#include <GeomAPI_Pnt.h>
#include <GeomAPI_Shape.h>
+#include <GeomAPI_ShapeIterator.h>
#include <TDF_AttributeIterator.hxx>
#include <TDF_ChildIterator.hxx>
#include <TDF_RelocationTable.hxx>
#include <TDF_DeltaOnAddition.hxx>
+#include <TDataStd_UAttribute.hxx>
#include <TopAbs_ShapeEnum.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Shape.hxx>
#include <TNaming_NamedShape.hxx>
#include <NCollection_List.hxx>
+/// GUID for UAttribute that indicates the list has "To add all elements that share the same
+/// topology" flag enabled
+static const Standard_GUID kIS_GEOMETRICAL_SELECTION("f16987b6-e6c8-435c-99fa-03a7e0b06e83");
+
void Model_AttributeSelectionList::append(
const ObjectPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape,
const bool theTemporarily)
{
int anOldSize = mySize->Get();
int aRemoved = 0;
- // iterate one by one and shifting the removed indicies
+ // iterate one by one and shifting the removed indices
for(int aCurrent = 0; aCurrent < anOldSize; aCurrent++) {
if (theIndices.find(aCurrent) == theIndices.end()) { // not removed
if (aRemoved) { // but must be shifted to the removed position
return mySize->Get();
}
+// returns true if theShape is same with theInList or is contained in it (a compound)
+static bool isIn(GeomShapePtr theInList, GeomShapePtr theShape) {
+ if (theShape->isSame(theInList))
+ return true;
+ if (theInList.get() && theInList->shapeType() == GeomAPI_Shape::COMPOUND) {
+ for(GeomAPI_ShapeIterator anIter(theInList); anIter.more(); anIter.next()) {
+ if (!anIter.current()->isNull() && anIter.current()->isSame(theShape))
+ return true;
+ }
+ }
+ return false;
+}
+
bool Model_AttributeSelectionList::isInList(const ObjectPtr& theContext,
const std::shared_ptr<GeomAPI_Shape>& theSubShape,
const bool theTemporarily)
return true;
} else {
// we need to call here isSame instead of isEqual to do not check shapes orientation
- if (theSubShape->isSame(*aShapes))
+ if (isIn(*aShapes, theSubShape))
return true;
}
}
}
} else {
// we need to call here isSame instead of isEqual to do not check shapes orientation
- if (theSubShape->isSame(aValue)) // shapes are equal
+ if (isIn(aValue, theSubShape)) // shapes are equal
return true;
}
}
}
TDF_Label aLabel = mySize->Label().FindChild(theIndex + 1);
// create a new attribute each time, by demand
- // supporting of old attributes is too slow (synch each time) and buggy on redo
- // (if attribute is deleted and created, the abort updates attriute and makes the Attr invalid)
+ // supporting of old attributes is too slow (sync each time) and buggy on redo
+ // (if attribute is deleted and created, the abort updates attribute and makes the Attr invalid)
std::shared_ptr<Model_AttributeSelection> aNewAttr =
std::shared_ptr<Model_AttributeSelection>(new Model_AttributeSelection(aLabel));
if (owner()) {
}
Model_AttributeSelectionList::Model_AttributeSelectionList(TDF_Label& theLabel)
-: myLab(theLabel),
- myIsGeometricalSelection(false)
+: myLab(theLabel)
{
reinit();
}
}
}
+bool Model_AttributeSelectionList::isGeometricalSelection() const
+{
+ return myLab.IsAttribute(kIS_GEOMETRICAL_SELECTION);
+}
+
void Model_AttributeSelectionList::setGeometricalSelection(const bool theIsGeometricalSelection)
{
- myIsGeometricalSelection = theIsGeometricalSelection;
- // TODO: update list accodring to the flag:
- // false - all objects with same geometry must be splited in separate.
- // true - all objets with same geometry must be combined into single.
+ if (isGeometricalSelection() == theIsGeometricalSelection)
+ return; // nothing to do
+ if (theIsGeometricalSelection) // store the state
+ TDataStd_UAttribute::Set(myLab, kIS_GEOMETRICAL_SELECTION);
+ else
+ myLab.ForgetAttribute(kIS_GEOMETRICAL_SELECTION);
+ std::set<int> anIndiciesToRemove; // Update list according to the flag
+ if (theIsGeometricalSelection) { // all objects with same geometry must be combined into single
+ std::list<AttributeSelectionPtr> anAttributes; // collect attributes with geometrical compounds
+ for(int anIndex = 0; anIndex < size(); anIndex++) {
+ AttributeSelectionPtr anAttr = value(anIndex);
+ if (!anAttr.get() || !anAttr->context().get())
+ continue;
+ anAttr->combineGeometrical();
+ if (!anAttr->value().get() || anAttr->value()->shapeType() != GeomAPI_Shape::COMPOUND)
+ continue;
+ // check it is equal to some other attribute already presented in the list
+ std::list<AttributeSelectionPtr>::iterator anAttrIter = anAttributes.begin();
+ for(; anAttrIter != anAttributes.end(); anAttrIter++) {
+ if (anAttr->context() == (*anAttrIter)->context() &&
+ anAttr->namingName() == (*anAttrIter)->namingName()) {
+ anIndiciesToRemove.insert(anIndex);
+ break;
+ }
+ }
+ if (anAttrIter == anAttributes.end()) // not removed, so, add to the compare-list
+ anAttributes.push_back(anAttr);
+ }
+ } else { // all objects with same geometry must be divided into separated sub-attributes
+ int anInitialSize = size();
+ for(int anIndex = 0; anIndex < anInitialSize; anIndex++) {
+ AttributeSelectionPtr anAttr = value(anIndex);
+ if (!anAttr.get() || !anAttr->context().get())
+ continue;
+ GeomShapePtr aValue = anAttr->value();
+ if (!aValue.get() || aValue->shapeType() != GeomAPI_Shape::COMPOUND)
+ continue;
+ for(GeomAPI_ShapeIterator anIter(aValue); anIter.more(); anIter.next()) {
+ append(anAttr->context(), anIter.current());
+ }
+ anIndiciesToRemove.insert(anIndex);
+ }
+ }
+ remove(anIndiciesToRemove);
+ myIsCashed = false;
+ myCash.clear(); // empty list as indicator that cash is not used
+ owner()->data()->sendAttributeUpdated(this);
}
/// the cashed shapes to optimize isInList method: from context to set of shapes in this context
std::map<ResultPtr, std::list<std::shared_ptr<GeomAPI_Shape> > > myCash;
bool myIsCashed; ///< true if cashing is performed
- /// If true attribute selects geometry instead of shape.
- bool myIsGeometricalSelection;
public:
/// Adds the new reference to the end of the list
/// \param theContext object where the sub-shape was selected
/// \param theSubShape selected sub-shape (if null, the whole context is selected)
/// \param theTemporarily if it is true, do not store and name the added in the data framework
- /// (used to remove immideately, without the following updates)
+ /// (used to remove immediately, without the following updates)
MODEL_EXPORT virtual void append(
const ObjectPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape,
const bool theTemporarily = false);
/// \param theIndices a list of indices of elements to be removed
MODEL_EXPORT virtual void remove(const std::set<int>& theIndices);
- /// Returns the number ofselection attributes in the list
+ /// Returns the number of selection attributes in the list
MODEL_EXPORT virtual int size();
/// Returns true if the object with the shape are in list
/// \param theContext object where the sub-shape was selected
/// \param theSubShape selected sub-shape (if null, the whole context is selected)
/// \param theTemporarily if it is true, it checks also the temporary added item
- /// \returns true if the pair is found in the attirbute
+ /// \returns true if the pair is found in the attribute
MODEL_EXPORT virtual bool isInList(
const ObjectPtr& theContext, const std::shared_ptr<GeomAPI_Shape>& theSubShape,
const bool theTemporarily = false);
MODEL_EXPORT virtual void setGeometricalSelection(const bool theIsGeometricalSelection) override;
/// Returns true if is geometrical selection.
- MODEL_EXPORT virtual bool isGeometricalSelection() const override {
- return myIsGeometricalSelection;
- };
+ MODEL_EXPORT virtual bool isGeometricalSelection() const override;
protected:
/// Objects are created for features automatically
return aResult;
}
+bool Model_ResultPart::combineGeometrical(const int theIndex, std::string& theNewName)
+{
+ std::shared_ptr<Model_Document> aDoc = std::dynamic_pointer_cast<Model_Document>(partDoc());
+ if (aDoc.get()) {
+ AttributeSelectionListPtr aSelAttr = aDoc->selectionInPartFeature();
+ AttributeSelectionPtr aThisAttr = aSelAttr->value(theIndex - 1);
+ if (aThisAttr.get()) {
+ aThisAttr->combineGeometrical();
+ if (aThisAttr->value().get()) {
+ int anIndex;
+ theNewName = nameInPart(aThisAttr->value(), anIndex);
+ return true;
+ }
+ }
+ }
+ return false; // something is wrong
+}
+
std::shared_ptr<GeomAPI_Shape> Model_ResultPart::shapeInPart(
const std::string& theName, const std::string& theType, int& theIndex)
{
/// Returns the shape by the name in the part
MODEL_EXPORT virtual std::shared_ptr<GeomAPI_Shape> shapeInPart(
const std::string& theName, const std::string& theType, int& theIndex);
+ /// Updates the selection inside of the part as a geometrical selection
+ MODEL_EXPORT virtual bool combineGeometrical(const int theIndex, std::string& theNewName);
/// Updates the shape-result of the part (called on Part feature execution)
MODEL_EXPORT virtual void updateShape();
/// Applies the additional transformation of the part
/// Returns the name by context. Adds the part name if the context is located in other document
MODELAPI_EXPORT virtual std::string contextName(const ResultPtr& theContext) const = 0;
+ /// Makes the current local selection becomes all sub-shapes with same base geometry.
+ MODELAPI_EXPORT virtual void combineGeometrical() = 0;
protected:
/// Objects are created for features automatically
virtual std::shared_ptr<GeomAPI_Shape> shapeInPart(
const std::string& theName, const std::string& theType, int& theIndex) = 0;
+ /// Updates the selection inside of the part as a geometrical selection
+ virtual bool combineGeometrical(const int theIndex, std::string& theNewName) = 0;
+
/// Returns the shape selected in the selection index
virtual std::shared_ptr<GeomAPI_Shape> selectionValue(const int theIndex) = 0;
aMainLay->addWidget(myListView->getControl(), 2, 0, 1, -1);
aMainLay->setRowStretch(2, 1);
- //aMainLay->addWidget(new QLabel(this)); //FIXME(sbh)???
- //aMainLay->setRowMinimumHeight(3, 20);
- //this->setLayout(aMainLay);
connect(myTypeCtrl, SIGNAL(valueChanged(int)), this, SLOT(onSelectionTypeChanged()));
bool aSameTop = theData->getBooleanAttribute("same_topology", false);
return false;
AttributePtr anAttribute = myFeature->data()->attribute(attributeID());
+ AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID());
std::string aType = anAttribute->attributeType();
if (aType == ModelAPI_AttributeSelectionList::typeId()) {
- AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID());
// Restore shape type
std::string aSelectionType = aSelectionListAttr->selectionType().c_str();
if (!aSelectionType.empty()) {
myIsFirst = false;
}
}
+ myGeomCheck->setChecked(aSelectionListAttr->isGeometricalSelection());
updateSelectionList();
return true;
}
std::string aType = anAttribute->attributeType();
if (aType == ModelAPI_AttributeSelectionList::typeId()) {
AttributeSelectionListPtr aSelectionListAttr = myFeature->data()->selectionList(attributeID());
- //TODO: set same topology flag
aSelectionListAttr->setGeometricalSelection(theOn);
updateObject(myFeature);
}
Selector_Selector::Selector_Selector(TDF_Label theLab) : myLab(theLab)
{
myWeakIndex = -1;
+ myAlwaysGeometricalNaming = false;
}
TDF_Label Selector_Selector::label()
{ // iterate all sub-shapes and select them on sublabels
for(TopoDS_Iterator aSubIter(theValue); aSubIter.More(); aSubIter.Next()) {
if (!selectBySubSelector(theContext, aSubIter.Value(),
- theGeometricalNaming, theUseNeighbors, theUseIntersections)) {
+ false, theUseNeighbors, theUseIntersections)) {//for subs no geometrical naming allowed
return false; // if some selector is failed, everything is failed
}
}
}
}
- // weak naming to distinguish commons coming from intersection
if (aLastCommon.Extent() > 1) {
+ if (myAlwaysGeometricalNaming) {
+ TopoDS_ListOfShape::Iterator aCommonIter(aLastCommon);
+ TopoDS_Shape aFirst = aCommonIter.Value();
+ for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
+ if (!sameGeometry(aFirst, aCommonIter.Value()))
+ break;
+ }
+ if (!aCommonIter.More()) { // all geometry is same, result is a compound
+ myType = SELTYPE_INTERSECT;
+ return true;
+ }
+ }
+ // weak naming to distinguish commons coming from intersection
Selector_NExplode aNexp(aLastCommon);
myWeakIndex = aNexp.index(theValue);
if (myWeakIndex != -1) {
findModificationResult(aCommon);
// trying to search by neighbors
if (aCommon.Extent() > 1) { // more complicated selection
+ if (myAlwaysGeometricalNaming) {
+ TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
+ TopoDS_Shape aFirst = aCommonIter.Value();
+ for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
+ if (!sameGeometry(aFirst, aCommonIter.Value()))
+ break;
+ }
+ if (!aCommonIter.More()) { // all geometry is same, result is a compound
+ myType = SELTYPE_MODIFICATION;
+ return true;
+ }
+ }
if (!theUseNeighbors)
return false;
}
}
// filter by neighbors did not help
- if (aCommon.Extent() > 1) { // weak naming between the common results
+ if (aCommon.Extent() > 1) {
+ if (myAlwaysGeometricalNaming) {
+ TopoDS_ListOfShape::Iterator aCommonIter(aCommon);
+ TopoDS_Shape aFirst = aCommonIter.Value();
+ for(aCommonIter.Next(); aCommonIter.More(); aCommonIter.Next()) {
+ if (!sameGeometry(aFirst, aCommonIter.Value()))
+ break;
+ }
+ if (!aCommonIter.More()) { // all geometry is same, result is a compound
+ myType = SELTYPE_FILTER_BY_NEIGHBOR;
+ return true;
+ }
+ }
+ // weak naming between the common results
Selector_NExplode aNexp(aCommon);
myWeakIndex = aNexp.index(theValue);
if (myWeakIndex == -1)
}
return true;
}
+
+void Selector_Selector::combineGeometrical(const TopoDS_Shape theContext)
+{
+ TopoDS_Shape aValue = value();
+ if (aValue.IsNull() || aValue.ShapeType() == TopAbs_COMPOUND)
+ return;
+ myAlwaysGeometricalNaming = true;
+ mySubSelList.clear();
+ myBases.Clear();
+ myWeakIndex = -1;
+ if (select(theContext, aValue, true)) {
+ store();
+ solve(theContext);
+ return;
+ }
+ // if can not select, select the compound in a custom way
+ TopTools_MapOfShape aMap;
+ TopoDS_ListOfShape aList;
+ for(TopExp_Explorer anExp(theContext, aValue.ShapeType()); anExp.More(); anExp.Next()) {
+ if (aMap.Add(anExp.Current())) {
+ if (sameGeometry(aValue, anExp.Current()))
+ aList.Append(anExp.Current());
+ }
+ }
+ if (aList.Size() > 1) {
+ TopoDS_Builder aBuilder;
+ TopoDS_Compound aCompound;
+ aBuilder.MakeCompound(aCompound);
+ for(TopoDS_ListIteratorOfListOfShape aListIter(aList); aListIter.More(); aListIter.Next()) {
+ aBuilder.Add(aCompound, aListIter.Value());
+ }
+ if (select(theContext, aCompound, true)) {
+ store();
+ solve(theContext);
+ }
+ }
+}
TDF_Label myBaseDocumentLab; ///< an access-label to the document that may contain initial shapes
bool myGeometricalNaming; ///< flag that indicates that geometrical naming selection is enabled
+ bool myAlwaysGeometricalNaming; /// to enable geometrical naming from beginning, at select
public:
/// Initializes selector on the label
/// Returns the naming name of the selection
SELECTOR_EXPORT std::string name(Selector_NameGenerator* theNameGenerator);
+ /// Makes the current local selection becomes all sub-shapes with same base geometry.
+ SELECTOR_EXPORT void combineGeometrical(const TopoDS_Shape theContext);
+
private:
/// Create and keep in the list the sub-selector that select the given value.