-// Copyright (C) 2014-2017 CEA/DEN, EDF R&D
+// Copyright (C) 2014-2024 CEA, EDF
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
-// See http://www.salome-platform.org/ or
-// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
#include <Model_BodyBuilder.h>
+#include <Locale_Convert.h>
+
#include <Model_Data.h>
#include <Model_Document.h>
#include <ModelAPI_Session.h>
case TopAbs_VERTEX: return GENERATED_VERTICES_TAG;
case TopAbs_EDGE: return GENERATED_EDGES_TAG;
case TopAbs_FACE: return GENERATED_FACES_TAG;
+ default: break; // [to avoid compilation warning]
}
return INVALID_TAG;
case TopAbs_VERTEX: return MODIFIED_VERTICES_TAG;
case TopAbs_EDGE: return MODIFIED_EDGES_TAG;
case TopAbs_FACE: return MODIFIED_FACES_TAG;
+ default: break; // [to avoid compilation warning]
}
return INVALID_TAG;
if (aResult) { //check evolution and a label of this shape
for(TNaming_SameShapeIterator aShapes(theShape, theAccess1); aShapes.More(); aShapes.Next())
{
- static Handle(TNaming_NamedShape) aNS;
+ Handle(TNaming_NamedShape) aNS;
if (aShapes.Label().FindAttribute(TNaming_NamedShape::GetID(), aNS)) {
if (aNS->Evolution() != TNaming_SELECTED) {
theOriginalLabel = aNS->Label();
return; // null shape inside
if(!theIsStoreSameShapes) {
- Handle(TNaming_NamedShape) aNS = TNaming_Tool::NamedShape(aShape, aShapeLab);
+ Handle(TNaming_NamedShape) aNS;
+ if (TNaming_Tool::HasLabel(aShapeLab, aShape))
+ aNS = TNaming_Tool::NamedShape(aShape, aShapeLab);
// the last condition is for the issue 2751 : existing shape may be found in compound-NS
if(!aNS.IsNull() && !aNS->IsEmpty() && aNS->Get().IsSame(aShape)) {
// This shape is already in document, store reference instead of shape;
if(!aBuilder.NamedShape()->IsEmpty()) {
Handle(TDataStd_Name) anAttr;
if(aBuilder.NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
- std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
+ std::wstring aName = Locale::Convert::toWString(anAttr->Get().ToExtString());
if(!aName.empty()) {
std::shared_ptr<Model_Document> aDoc =
std::dynamic_pointer_cast<Model_Document>(document());
{
std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
if (aData) {
- TDF_Label aShapeLab = aData->shapeLab();
// clean builders
if (theIsCleanStored)
clean();
if(!aBuilder->NamedShape()->IsEmpty()) {
Handle(TDataStd_Name) anAttr;
if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(),anAttr)) {
- std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
+ std::wstring aName = Locale::Convert::toWString(anAttr->Get().ToExtString());
if(!aName.empty()) {
std::shared_ptr<Model_Document> aDoc =
std::dynamic_pointer_cast<Model_Document>(document());
}
}
+static TDF_Label builderLabel(DataPtr theData, const int theTag )
+{
+ std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theData);
+ return theTag == 0 ? aData->shapeLab() : aData->shapeLab().FindChild(theTag);
+}
+
TNaming_Builder* Model_BodyBuilder::builder(const int theTag)
{
std::map<int, TNaming_Builder*>::iterator aFind = myBuilders.find(theTag);
if (aFind == myBuilders.end()) {
- std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
- myBuilders[theTag] = new TNaming_Builder(
- theTag == 0 ? aData->shapeLab() : aData->shapeLab().FindChild(theTag));
+ myBuilders[theTag] = new TNaming_Builder(builderLabel(data(), theTag));
aFind = myBuilders.find(theTag);
}
return aFind->second;
TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(
ModelAPI_Session::get()->moduleDocument())->generalLabel();
TDF_Label anOriginalLabel;
+ TopTools_ListOfShape anOldList;
if (!isShapeInTree(aData->shapeLab(), anAccess2, aShapeOld, anOriginalLabel)) {
+ // check this could be a compund by the whole feature selection
+ if (aShapeOld.ShapeType() == TopAbs_COMPOUND) {
+ for(TopoDS_Iterator aCompIter(aShapeOld); aCompIter.More(); aCompIter.Next()) {
+ if (isShapeInTree(aData->shapeLab(), anAccess2, aCompIter.Value(), anOriginalLabel)) {
+ anOldList.Append(aCompIter.Value());
+ } else {
+ anOldList.Clear();
+ break;
+ }
+ }
+ }
+ } else {
+ anOldList.Append(aShapeOld);
+ }
+ if (anOldList.IsEmpty()) {
if (aBuilder->NamedShape()->Get().IsNull()) { // store as primitive if alone anyway
aBuilder->Generated(aShapeNew);
}
myBuilders.erase(0);
aBuilder = builder(0);
}
-
- aBuilder->Modify(aShapeOld, aShapeNew);
+ TopTools_ListIteratorOfListOfShape anOldIter(anOldList);
+ for(; anOldIter.More(); anOldIter.Next()) {
+ aBuilder->Modify(anOldIter.Value(), aShapeNew);
+ }
// store information about the external document reference to restore old shape on open
storeExternalReference(anOriginalLabel, aBuilder->NamedShape()->Label());
}
if(!aBuilder->NamedShape()->IsEmpty()) {
Handle(TDataStd_Name) anAttr;
if(aBuilder->NamedShape()->Label().FindAttribute(TDataStd_Name::GetID(), anAttr)) {
- std::string aName (TCollection_AsciiString(anAttr->Get()).ToCString());
+ std::wstring aName = Locale::Convert::toWString(anAttr->Get().ToExtString());
if(!aName.empty()) {
std::shared_ptr<Model_Document> aDoc =
std::dynamic_pointer_cast<Model_Document>(document());
std::list<GeomShapePtr>::const_iterator anOldIter = theOldShapes.cbegin();
for(; anOldIter != theOldShapes.cend(); anOldIter++) {
// compounds may cause crash if call "modified"
- bool aStore = (*anOldIter)->isCompound() || (*anOldIter)->isShell() || (*anOldIter)->isWire();
+ bool aStore = (*anOldIter)->isCompound() || (*anOldIter)->isShell() || (*anOldIter)->isWire() ||
+ (*anOldIter)->isCompSolid();
if (!aStore) {
ListOfShape aNews; // check this old really modifies theNewShape
theMakeShape->modified(*anOldIter, aNews);
aStored = !aBuilder->NamedShape()->IsEmpty();
}
}
- if (!aStored) { // store as PRIMITIVE, but clean in any way
- store(theNewShape);
+ if (!aStored) {
+ // check the new shape is already in the tree, so, no need to store primitive, just reference
+ std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
+ if (aData.get()) {
+ TDF_Label aShapeLab = aData->shapeLab();
+ TopoDS_Shape aShapeNew = theNewShape->impl<TopoDS_Shape>();
+ Handle(TNaming_NamedShape) aNS;
+ if (TNaming_Tool::HasLabel(aShapeLab, aShapeNew))
+ aNS = TNaming_Tool::NamedShape(aShapeNew, aShapeLab);
+ // the last condition is for the issue 2751 : existing shape may be found in compound-NS
+ if (!aNS.IsNull() && !aNS->IsEmpty() && aNS->Get().IsSame(aShapeNew)) {
+ // This shape is already in document, store reference instead of shape;
+ const TDF_Label aFoundLabel = aNS->Label();
+ TDF_Reference::Set(aShapeLab, aFoundLabel);
+ myBuilders.erase(0);
+ aShapeLab.ForgetAttribute(TNaming_NamedShape::GetID());
+ return;
+ }
+ }
+ store(theNewShape); // store as PRIMITIVE, but clean in any way
return;
}
}
}
aName.insert(0, aPrefix);
- TDataStd_Name::Set(builder(theTag)->NamedShape()->Label(), aName.c_str());
+ TDataStd_Name::Set(builderLabel(data(), theTag), aName.c_str());
}
bool Model_BodyBuilder::generated(const GeomShapePtr& theNewShape,
const std::string& theName,
if (aNewShapeType == TopAbs_WIRE || aNewShapeType == TopAbs_SHELL) {
// TODO: This is a workaround. New shape should be only vertex, edge or face.
TopAbs_ShapeEnum aShapeTypeToExplore = aNewShapeType == TopAbs_WIRE ? TopAbs_EDGE : TopAbs_FACE;
- aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
+ aTag = aNewShapeType == TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
for (TopExp_Explorer anExp(aNewShape, aShapeTypeToExplore); anExp.More(); anExp.Next()) {
builder(aTag)->Generated(anOldShape, anExp.Current());
}
if (aCompound.get()) aShapeToExplore = aCompound;
}
+ // Store all types of subshapes in the map to use them for checking
+ // if the new shapes are sub-shapes of this result
+ TopTools_MapOfShape aResultShapeSubMap;
+ TopExp::MapShapes(aResultShape->impl<TopoDS_Shape>(), aResultShapeSubMap);
+
TopTools_MapOfShape anAlreadyProcessedShapes;
std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(data());
for (GeomAPI_ShapeExplorer anOldShapeExp(aShapeToExplore, theShapeTypeToExplore);
// There is no sense to write history if shape already processed
// or old shape does not exist in the document.
- bool anOldSubShapeAlreadyProcessed = !anAlreadyProcessedShapes.Add(anOldSubShape_);
- TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(
- ModelAPI_Session::get()->moduleDocument())->generalLabel();
+ if (!anAlreadyProcessedShapes.Add(anOldSubShape_))
+ {
+ continue;
+ }
+
+ TDF_Label anAccess2 = std::dynamic_pointer_cast<Model_Document>(ModelAPI_Session::get()->moduleDocument())->generalLabel();
TDF_Label anOriginalLabel;
- bool anOldSubShapeNotInTree =
- !isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel);
- if (anOldSubShapeAlreadyProcessed || anOldSubShapeNotInTree) {
+ if (!isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel))
+ {
continue;
}
// Get new shapes.
ListOfShape aNewShapes;
theAlgo->modified(anOldSubShape, aNewShapes);
-
for (ListOfShape::const_iterator aNewShapesIt = aNewShapes.cbegin();
aNewShapesIt != aNewShapes.cend();
++aNewShapesIt)
{
GeomShapePtr aNewShape = *aNewShapesIt;
const TopoDS_Shape& aNewShape_ = aNewShape->impl<TopoDS_Shape>();
- bool isGenerated = anOldSubShape_.ShapeType() != aNewShape_.ShapeType();
- bool aNewShapeIsSameAsOldShape = anOldSubShape->isSame(aNewShape);
- bool aNewShapeIsNotInResultShape = !aResultShape->isSubShape(aNewShape, false);
- if (aNewShapeIsSameAsOldShape || aNewShapeIsNotInResultShape)
+ if (anOldSubShape->isSame(aNewShape))
continue;
if (aResultShape->isSame(aNewShape))
continue; // it is stored on the root level (2241 - history propagation issue)
+ // Look in the map instead of aResultShape->isSubShape(aNewShape, false)
+ // to avoid many iterations of sub-shapes hierarchy that leads to performance issues
+ if (!aResultShapeSubMap.Contains(aNewShape_))
+ continue;
+
+ const bool isGenerated = anOldSubShape_.ShapeType() != aNewShape_.ShapeType();
int aTag = isGenerated ? getGenerationTag(aNewShape_) : getModificationTag(aNewShape_);
TNaming_Builder*aBuilder = builder(aTag);
if (isAlreadyStored(aBuilder, anOldSubShape_, aNewShape_))
void Model_BodyBuilder::loadGeneratedShapes(const GeomMakeShapePtr& theAlgo,
const GeomShapePtr& theOldShape,
const GeomAPI_Shape::ShapeType theShapeTypeToExplore,
- const std::string& theName)
+ const std::string& theName,
+ const bool theSaveOldIfNotInTree)
{
GeomShapePtr aResultShape = shape();
TopTools_MapOfShape anAlreadyProcessedShapes;
bool anOldSubShapeNotInTree =
!isShapeInTree(aData->shapeLab(), anAccess2, anOldSubShape_, anOriginalLabel);
if (anOldSubShapeAlreadyProcessed || anOldSubShapeNotInTree) {
- continue;
+ // The second condition is added due to #20170 because sub-shape must be added to real parent
+ // shape, not the reference. The naming name of pure reference is not registered in document.
+ if (theSaveOldIfNotInTree && !aData->shapeLab().IsAttribute(TDF_Reference::GetID())) {
+ std::string aSelectionName = theName + "Selected";
+ generated(anOldSubShape, aSelectionName, false);
+ } else
+ continue;
}
// Get new shapes.
continue;
}
+ if (aResultShape->isSame(aNewShape))
+ continue; // it is stored on the root level
+
TopAbs_ShapeEnum aNewShapeType = aNewShape_.ShapeType();
if (aNewShapeType == TopAbs_WIRE || aNewShapeType == TopAbs_SHELL) {
// TODO: This is a workaround. New shape should be only edge or face.
TopAbs_ShapeEnum aShapeTypeToExplore = aNewShapeType == TopAbs_WIRE ? TopAbs_EDGE
: TopAbs_FACE;
- int aTag = TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
+ int aTag = aNewShapeType == TopAbs_WIRE ? GENERATED_EDGES_TAG : GENERATED_FACES_TAG;
for (TopExp_Explorer anExp(aNewShape_, aShapeTypeToExplore); anExp.More(); anExp.Next()) {
builder(aTag)->Generated(anOldSubShape_, anExp.Current());
// store information about the external document reference to restore old shape on open
- storeExternalReference(anOriginalLabel, builder(aTag)->NamedShape()->Label());
+ storeExternalReference(anOriginalLabel, builderLabel(data(), aTag));
}
buildName(aTag, theName);
} else {
builder(aTag)->Generated(anOldSubShape_, aNewShape_);
buildName(aTag, theName);
// store information about the external document reference to restore old shape on open
- storeExternalReference(anOriginalLabel, builder(aTag)->NamedShape()->Label());
+ storeExternalReference(anOriginalLabel, builderLabel(data(), aTag));
}
}
}
//=======================================================================
void Model_BodyBuilder::loadFirstLevel(GeomShapePtr theShape, const std::string& theName)
{
- if(theShape->isNull()) return;
- TopoDS_Shape aShape = theShape->impl<TopoDS_Shape>();
+ GeomShapePtr aShapePtr = shape();
+ if (theShape->isNull() || !aShapePtr.get())
+ return;
+ TopoDS_Shape aShape = shape()->impl<TopoDS_Shape>();
+ if (aShape.IsNull())
+ return;
std::string aName;
if (aShape.ShapeType() == TopAbs_COMPOUND || aShape.ShapeType() == TopAbs_COMPSOLID) {
TopoDS_Iterator itr(aShape);