From 93310e00f0ac95395137c842108790bf62e6425e Mon Sep 17 00:00:00 2001 From: mpv Date: Fri, 3 Oct 2014 09:21:58 +0400 Subject: [PATCH] Added a selection attribute and naming basic mechanisms --- src/GeomAPI/GeomAPI_Shape.cpp | 12 ++++- src/GeomAPI/GeomAPI_Shape.h | 7 ++- src/Model/CMakeLists.txt | 4 +- src/Model/Model_AttributeReference.h | 1 + src/Model/Model_AttributeSelection.cpp | 60 ++++++++++++++++++++++ src/Model/Model_AttributeSelection.h | 38 ++++++++++++++ src/Model/Model_Document.cpp | 30 +++++------ src/Model/Model_ResultBody.cpp | 60 +++++++++++++++++++++- src/Model/Model_ResultBody.h | 41 ++++++++++++++- src/ModelAPI/CMakeLists.txt | 1 + src/ModelAPI/ModelAPI.i | 7 ++- src/ModelAPI/ModelAPI_AttributeSelection.h | 53 +++++++++++++++++++ src/ModelAPI/ModelAPI_Object.h | 2 + src/ModelAPI/ModelAPI_ResultBody.h | 39 ++++++++++---- src/ModelAPI/ModelAPI_Session.cpp | 1 + 15 files changed, 322 insertions(+), 34 deletions(-) create mode 100644 src/Model/Model_AttributeSelection.cpp create mode 100644 src/Model/Model_AttributeSelection.h create mode 100644 src/ModelAPI/ModelAPI_AttributeSelection.h diff --git a/src/GeomAPI/GeomAPI_Shape.cpp b/src/GeomAPI/GeomAPI_Shape.cpp index e51d30ca6..0e5bcb010 100644 --- a/src/GeomAPI/GeomAPI_Shape.cpp +++ b/src/GeomAPI/GeomAPI_Shape.cpp @@ -13,11 +13,21 @@ GeomAPI_Shape::GeomAPI_Shape() { } -bool GeomAPI_Shape::isNull() +bool GeomAPI_Shape::isNull() const { return MY_SHAPE->IsNull() == Standard_True; } +bool GeomAPI_Shape::isEqual(const boost::shared_ptr theShape) const +{ + if (isNull()) + return theShape->isNull(); + if (theShape->isNull()) + return false; + + return MY_SHAPE->IsEqual(theShape->impl()) == Standard_True; +} + bool GeomAPI_Shape::isVertex() const { const TopoDS_Shape& aShape = const_cast(this)->impl(); diff --git a/src/GeomAPI/GeomAPI_Shape.h b/src/GeomAPI/GeomAPI_Shape.h index c2e3507b4..3aa0987f7 100644 --- a/src/GeomAPI/GeomAPI_Shape.h +++ b/src/GeomAPI/GeomAPI_Shape.h @@ -6,6 +6,7 @@ #define GeomAPI_Shape_H_ #include +#include /**\class GeomAPI_Shape * \ingroup DataModel @@ -17,7 +18,10 @@ class GEOMAPI_EXPORT GeomAPI_Shape : public GeomAPI_Interface /// Creation of empty (null) shape GeomAPI_Shape(); - bool isNull(); + bool isNull() const; + + /// Returns whether the shapes are equal + virtual bool isEqual(const boost::shared_ptr theShape) const; /// Returns whether the shape is a vertex virtual bool isVertex() const; @@ -28,4 +32,3 @@ class GEOMAPI_EXPORT GeomAPI_Shape : public GeomAPI_Interface }; #endif - diff --git a/src/Model/CMakeLists.txt b/src/Model/CMakeLists.txt index 69a821ac3..c9715ebc2 100644 --- a/src/Model/CMakeLists.txt +++ b/src/Model/CMakeLists.txt @@ -14,6 +14,7 @@ SET(PROJECT_HEADERS Model_AttributeBoolean.h Model_AttributeString.h Model_AttributeInteger.h + Model_AttributeSelection.h Model_Events.h Model_Update.h Model_Validator.h @@ -36,6 +37,7 @@ SET(PROJECT_SOURCES Model_AttributeBoolean.cpp Model_AttributeString.cpp Model_AttributeInteger.cpp + Model_AttributeSelection.cpp Model_Events.cpp Model_Update.cpp Model_Validator.cpp @@ -60,7 +62,7 @@ SET(PROJECT_LIBRARIES ADD_DEFINITIONS(-DMODEL_EXPORTS ${CAS_DEFINITIONS} ${BOOST_DEFINITIONS}) -ADD_LIBRARY(Model MODULE ${PROJECT_SOURCES} ${PROJECT_HEADERS}) +ADD_LIBRARY(Model SHARED ${PROJECT_SOURCES} ${PROJECT_HEADERS}) TARGET_LINK_LIBRARIES(Model ${PROJECT_LIBRARIES}) INCLUDE_DIRECTORIES( diff --git a/src/Model/Model_AttributeReference.h b/src/Model/Model_AttributeReference.h index d9993f99a..b41891bdb 100644 --- a/src/Model/Model_AttributeReference.h +++ b/src/Model/Model_AttributeReference.h @@ -35,6 +35,7 @@ protected: MODEL_EXPORT Model_AttributeReference(TDF_Label& theLabel); friend class Model_Data; + friend class Model_AttributeSelection; }; #endif diff --git a/src/Model/Model_AttributeSelection.cpp b/src/Model/Model_AttributeSelection.cpp new file mode 100644 index 000000000..8c344e2b3 --- /dev/null +++ b/src/Model/Model_AttributeSelection.cpp @@ -0,0 +1,60 @@ +// File: Model_AttributeSelection.h +// Created: 2 Oct 2014 +// Author: Mikhail PONIKAROV + +#include "Model_AttributeSelection.h" +#include "Model_Application.h" +#include "Model_Events.h" +#include "Model_Data.h" +#include + +#include +#include +#include + +using namespace std; + +void Model_AttributeSelection::setValue(const ResultBodyPtr& theContext, + const boost::shared_ptr& theSubShape) +{ + const boost::shared_ptr& anOldShape = value(); + bool isOldShape = + (theSubShape == anOldShape || (theSubShape && anOldShape && theSubShape->isEqual(anOldShape))); + if (isOldShape) return; // shape is the same, so context is also unchanged + // update the referenced object if needed + bool isOldContext = theContext == myRef.value(); + if (!isOldContext) + myRef.setValue(theContext); + + // perform the selection + TNaming_Selector aSel(myRef.myRef->Label()); + TopoDS_Shape aNewShape = theSubShape ? theSubShape->impl() : TopoDS_Shape(); + TopoDS_Shape aContext = theContext->shape()->impl(); + aSel.Select(aNewShape, aContext); + myIsInitialized = true; + + owner()->data()->sendAttributeUpdated(this); +} + +boost::shared_ptr Model_AttributeSelection::value() +{ + boost::shared_ptr aResult; + if (myIsInitialized) { + Handle(TNaming_NamedShape) aSelection; + if (myRef.myRef->Label().FindAttribute(TNaming_NamedShape::GetID(), aSelection)) { + TopoDS_Shape aSelShape = aSelection->Get(); + aResult->setImpl(&aSelShape); + } + } + return aResult; +} + +Model_AttributeSelection::Model_AttributeSelection(TDF_Label& theLabel) + : myRef(theLabel) +{ + myIsInitialized = myRef.isInitialized(); +} + +ResultBodyPtr Model_AttributeSelection::context() { + return boost::dynamic_pointer_cast(myRef.value()); +} diff --git a/src/Model/Model_AttributeSelection.h b/src/Model/Model_AttributeSelection.h new file mode 100644 index 000000000..d8e8a54a7 --- /dev/null +++ b/src/Model/Model_AttributeSelection.h @@ -0,0 +1,38 @@ +// File: Model_AttributeSelection.h +// Created: 8 May 2014 +// Author: Mikhail PONIKAROV + +#ifndef Model_AttributeSelection_H_ +#define Model_AttributeSelection_H_ + +#include "Model.h" +#include "Model_AttributeReference.h" +#include + +/**\class Model_AttributeSelection + * \ingroup DataModel + * \brief Attribute that contains reference to the sub-shape of some result, the selected shape. + */ + +class Model_AttributeSelection : public ModelAPI_AttributeSelection +{ + Model_AttributeReference myRef; ///< The reference functionality reusage +public: + /// Defines the result and its selected sub-shape + MODEL_EXPORT virtual void setValue( + const ResultBodyPtr& theContext, const boost::shared_ptr& theSubShape); + + /// Returns the selected subshape + MODEL_EXPORT virtual boost::shared_ptr value(); + + /// Returns the context of the selection (the whole shape owner) + MODEL_EXPORT virtual ResultBodyPtr context(); + +protected: + /// Objects are created for features automatically + MODEL_EXPORT Model_AttributeSelection(TDF_Label& theLabel); + + friend class Model_Data; +}; + +#endif diff --git a/src/Model/Model_Document.cpp b/src/Model/Model_Document.cpp index e583a0fb8..59ebd2fb0 100644 --- a/src/Model/Model_Document.cpp +++ b/src/Model/Model_Document.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -49,11 +48,10 @@ Model_Document::Model_Document(const std::string theID, const std::string theKin : myID(theID), myKind(theKind), myDoc(new TDocStd_Document("BinOcaf")) // binary OCAF format { - myDoc->SetUndoLimit(UNDO_LIMIT); + myDoc->SetUndoLimit(UNDO_LIMIT); myTransactionsAfterSave = 0; myNestedNum = -1; myExecuteFeatures = true; - //myDoc->SetNestedTransactionMode(); // to have something in the document and avoid empty doc open/save problem // in transaction for nesting correct working myDoc->NewCommand(); @@ -822,15 +820,11 @@ void Model_Document::storeResult(boost::shared_ptr theFeatureData } } -static const Standard_GUID ID_CONSTRUCTION("b59fa408-8ab1-42b8-980c-af5adeebe7e4"); -static const Standard_GUID ID_BODY("c1148e9a-9b17-4e9c-9160-18e918fd0013"); -static const Standard_GUID ID_PART("1b3319b9-3e0a-4298-a1dc-3fb5aaf9be59"); - boost::shared_ptr Model_Document::createConstruction( const boost::shared_ptr& theFeatureData, const int theIndex) { TDF_Label aLab = resultLabel(theFeatureData, theIndex); - TDataStd_UAttribute::Set(aLab, ID_CONSTRUCTION); + TDataStd_Comment::Set(aLab, ModelAPI_ResultConstruction::group().c_str()); ObjectPtr anOldObject = object(aLab); boost::shared_ptr aResult; if (anOldObject) { @@ -847,7 +841,7 @@ boost::shared_ptr Model_Document::createBody( const boost::shared_ptr& theFeatureData, const int theIndex) { TDF_Label aLab = resultLabel(theFeatureData, theIndex); - TDataStd_UAttribute::Set(aLab, ID_BODY); + TDataStd_Comment::Set(aLab, ModelAPI_ResultBody::group().c_str()); ObjectPtr anOldObject = object(aLab); boost::shared_ptr aResult; if (anOldObject) { @@ -864,7 +858,7 @@ boost::shared_ptr Model_Document::createPart( const boost::shared_ptr& theFeatureData, const int theIndex) { TDF_Label aLab = resultLabel(theFeatureData, theIndex); - TDataStd_UAttribute::Set(aLab, ID_PART); + TDataStd_Comment::Set(aLab, ModelAPI_ResultPart::group().c_str()); ObjectPtr anOldObject = object(aLab); boost::shared_ptr aResult; if (anOldObject) { @@ -916,12 +910,16 @@ void Model_Document::updateResults(FeaturePtr theFeature) ResultPtr aNewBody; if (aResSize <= aResIndex) { TDF_Label anArgLab = aLabIter.Value(); - if (anArgLab.IsAttribute(ID_BODY)) { - aNewBody = createBody(theFeature->data(), aResIndex); - } else if (anArgLab.IsAttribute(ID_PART)) { - aNewBody = createPart(theFeature->data(), aResIndex); - } else if (!anArgLab.IsAttribute(ID_CONSTRUCTION) && anArgLab.FindChild(1).HasAttribute()) { - Events_Error::send("Unknown type of result is found in the document"); + Handle(TDataStd_Comment) aGroup; + if (anArgLab.FindAttribute(TDataStd_Comment::GetID(), aGroup)) { + if (aGroup->Get() == ModelAPI_ResultBody::group().c_str()) { + aNewBody = createBody(theFeature->data(), aResIndex); + } else if (aGroup->Get() == ModelAPI_ResultPart::group().c_str()) { + aNewBody = createPart(theFeature->data(), aResIndex); + } else if (aGroup->Get() != ModelAPI_ResultConstruction::group().c_str()) { + Events_Error::send(std::string("Unknown type of result is found in the document:") + + TCollection_AsciiString(aGroup->Get()).ToCString()); + } } if (aNewBody) { theFeature->setResult(aNewBody, aResIndex); diff --git a/src/Model/Model_ResultBody.cpp b/src/Model/Model_ResultBody.cpp index 967265f83..0409a4cc2 100644 --- a/src/Model/Model_ResultBody.cpp +++ b/src/Model/Model_ResultBody.cpp @@ -18,7 +18,10 @@ void Model_ResultBody::store(const boost::shared_ptr& theShape) boost::shared_ptr aData = boost::dynamic_pointer_cast(data()); if (aData) { TDF_Label& aShapeLab = aData->shapeLab(); - // TODO: to add the naming mechanism for shape storage in the next iteration + // remove the previous history + clean(); + aShapeLab.ForgetAllAttributes(); + // store the new shape as primitive TNaming_Builder aBuilder(aShapeLab); if (!theShape) return; // bad shape @@ -52,3 +55,58 @@ boost::shared_ptr Model_ResultBody::owner() { return myOwner; } + +void Model_ResultBody::clean() +{ + std::vector::iterator aBuilder = myBuilders.begin(); + for(; aBuilder != myBuilders.end(); aBuilder++) + delete *aBuilder; +} + +Model_ResultBody::~Model_ResultBody() +{ + clean(); +} + +TNaming_Builder* Model_ResultBody::builder(const int theTag) +{ + if (myBuilders.size() < (unsigned int)theTag) { + myBuilders.insert(myBuilders.end(), theTag - myBuilders.size() + 1, NULL); + } + if (!myBuilders[theTag]) { + boost::shared_ptr aData = boost::dynamic_pointer_cast(data()); + myBuilders[theTag] = new TNaming_Builder(aData->shapeLab().FindChild(theTag)); + } + return myBuilders[theTag]; +} + +void Model_ResultBody::generated( + const boost::shared_ptr& theNewShape, const int theTag) +{ + TopoDS_Shape aShape = theNewShape->impl(); + builder(theTag)->Generated(aShape); +} + +void Model_ResultBody::generated(const boost::shared_ptr& theOldShape, + const boost::shared_ptr& theNewShape, const int theTag) +{ + TopoDS_Shape anOldShape = theOldShape->impl(); + TopoDS_Shape aNewShape = theNewShape->impl(); + builder(theTag)->Generated(anOldShape, aNewShape); +} + + +void Model_ResultBody::modified(const boost::shared_ptr& theOldShape, + const boost::shared_ptr& theNewShape, const int theTag) +{ + TopoDS_Shape anOldShape = theOldShape->impl(); + TopoDS_Shape aNewShape = theNewShape->impl(); + builder(theTag)->Modify(anOldShape, aNewShape); +} + +void Model_ResultBody::deleted(const boost::shared_ptr& theOldShape, + const int theTag) +{ + TopoDS_Shape aShape = theOldShape->impl(); + builder(theTag)->Delete(aShape); +} diff --git a/src/Model/Model_ResultBody.h b/src/Model/Model_ResultBody.h index 08ce28ab0..c4ffbea31 100644 --- a/src/Model/Model_ResultBody.h +++ b/src/Model/Model_ResultBody.h @@ -7,6 +7,9 @@ #include "Model.h" #include +#include + +class TNaming_Builder; /**\class ModelAPI_ResultBody * \ingroup DataModel @@ -19,7 +22,10 @@ class Model_ResultBody : public ModelAPI_ResultBody { boost::shared_ptr myOwner; ///< owner of this result - public: + /// builders that tores the naming history: one per label to allow store several shapes to one + /// label; index in vector corresponds to the label tag + std::vector myBuilders; +public: /// Stores the shape (called by the execution method). MODEL_EXPORT virtual void store(const boost::shared_ptr& theShape); /// Returns the shape-result produced by this feature @@ -27,10 +33,41 @@ class Model_ResultBody : public ModelAPI_ResultBody /// Returns the source feature of this result MODEL_EXPORT virtual boost::shared_ptr owner(); - protected: + /// Records the subshape newShape which was generated during a topological construction. + /// As an example, consider the case of a face generated in construction of a box. + MODEL_EXPORT virtual void generated(const boost::shared_ptr& theNewShape, + const int theTag = 1); + + /// Records the shape newShape which was generated from the shape oldShape during a topological + /// construction. As an example, consider the case of a face generated from an edge in + /// construction of a prism. + MODEL_EXPORT virtual void generated(const boost::shared_ptr& theOldShape, + const boost::shared_ptr& theNewShape, const int theTag = 1); + + + /// Records the shape newShape which is a modification of the shape oldShape. + /// As an example, consider the case of a face split or merged in a Boolean operation. + MODEL_EXPORT virtual void modified(const boost::shared_ptr& theOldShape, + const boost::shared_ptr& theNewShape, const int theTag = 1); + + /// Records the shape oldShape which was deleted from the current label. + /// As an example, consider the case of a face removed by a Boolean operation. + MODEL_EXPORT virtual void deleted(const boost::shared_ptr& theOldShape, + const int theTag = 1); + + /// Removes the stored builders + MODEL_EXPORT virtual ~Model_ResultBody(); + +protected: /// Makes a body on the given feature Model_ResultBody(); + /// Removes the stored builders + void clean(); + + /// Returns (creates if necessary) the builder created on the needed tag of sub-label + TNaming_Builder* builder(const int theTag); + friend class Model_Document; }; diff --git a/src/ModelAPI/CMakeLists.txt b/src/ModelAPI/CMakeLists.txt index 9af7ad47a..b0299b5cf 100644 --- a/src/ModelAPI/CMakeLists.txt +++ b/src/ModelAPI/CMakeLists.txt @@ -20,6 +20,7 @@ SET(PROJECT_HEADERS ModelAPI_AttributeRefList.h ModelAPI_AttributeBoolean.h ModelAPI_AttributeString.h + ModelAPI_AttributeSelection.h ModelAPI_Events.h ModelAPI_Validator.h ModelAPI_FeatureValidator.h diff --git a/src/ModelAPI/ModelAPI.i b/src/ModelAPI/ModelAPI.i index a5bb73ebd..0eb00bd49 100644 --- a/src/ModelAPI/ModelAPI.i +++ b/src/ModelAPI/ModelAPI.i @@ -16,6 +16,7 @@ #include "ModelAPI_AttributeString.h" #include "ModelAPI_AttributeReference.h" #include "ModelAPI_AttributeRefAttr.h" + #include "ModelAPI_AttributeSelection.h" #include "ModelAPI_Validator.h" #include "ModelAPI_AttributeRefList.h" #include "ModelAPI_AttributeBoolean.h" @@ -60,6 +61,7 @@ %shared_ptr(ModelAPI_AttributeRefAttr) %shared_ptr(ModelAPI_AttributeRefList) %shared_ptr(ModelAPI_AttributeBoolean) +%shared_ptr(ModelAPI_AttributeSelection) %shared_ptr(ModelAPI_Result) %shared_ptr(ModelAPI_ResultConstruction) %shared_ptr(ModelAPI_ResultBody) @@ -80,13 +82,14 @@ %include "ModelAPI_AttributeString.h" %include "ModelAPI_AttributeReference.h" %include "ModelAPI_AttributeRefAttr.h" -%include "ModelAPI_Validator.h" +%include "ModelAPI_AttributeBoolean.h" +%include "ModelAPI_AttributeSelection.h" %include "ModelAPI_AttributeRefList.h" +%include "ModelAPI_Validator.h" %include "ModelAPI_Result.h" %include "ModelAPI_ResultConstruction.h" %include "ModelAPI_ResultBody.h" %include "ModelAPI_ResultPart.h" -%include "ModelAPI_AttributeBoolean.h" %template(ObjectList) std::list >; %template(ResultList) std::list >; diff --git a/src/ModelAPI/ModelAPI_AttributeSelection.h b/src/ModelAPI/ModelAPI_AttributeSelection.h new file mode 100644 index 000000000..9b4970c12 --- /dev/null +++ b/src/ModelAPI/ModelAPI_AttributeSelection.h @@ -0,0 +1,53 @@ +// File: ModelAPI_AttributeSelection.h +// Created: 2 Oct 2014 +// Author: Mikhail PONIKAROV + +#ifndef ModelAPI_AttributeSelection_H_ +#define ModelAPI_AttributeSelection_H_ + +#include "ModelAPI_Attribute.h" +#include + +/**\class ModelAPI_AttributeSelection + * \ingroup DataModel + * \brief Attribute that contains reference to the sub-shape of some result, the selected shape. + */ + +class ModelAPI_AttributeSelection : public ModelAPI_Attribute +{ + public: + /// Defines the result and its selected sub-shape + virtual void setValue( + const ResultBodyPtr& theContext, const boost::shared_ptr& theSubShape) = 0; + + /// Returns the selected subshape + virtual boost::shared_ptr value() = 0; + + /// Returns the context of the selection (the whole shape owner) + virtual ResultBodyPtr context() = 0; + + /// Returns the type of this class of attributes + static std::string type() + { + return "Selection"; + } + + /// Returns the type of this class of attributes, not static method + virtual std::string attributeType() + { + return type(); + } + + /// To virtually destroy the fields of successors + virtual ~ModelAPI_AttributeSelection() + { + } + + protected: + /// Objects are created for features automatically + MODELAPI_EXPORT ModelAPI_AttributeSelection() + { + } +}; + +#endif diff --git a/src/ModelAPI/ModelAPI_Object.h b/src/ModelAPI/ModelAPI_Object.h index 9241d9b65..a00d6e3b8 100644 --- a/src/ModelAPI/ModelAPI_Object.h +++ b/src/ModelAPI/ModelAPI_Object.h @@ -54,6 +54,8 @@ class ModelAPI_Object /// Returns the group identifier of this object virtual std::string groupName() = 0; + /// To use virtuality for destructors + virtual ~ModelAPI_Object() {} protected: /// Sets the data manager of an object (document does) virtual void setData(boost::shared_ptr theData) diff --git a/src/ModelAPI/ModelAPI_ResultBody.h b/src/ModelAPI/ModelAPI_ResultBody.h index c2eff7efc..bcd45b354 100644 --- a/src/ModelAPI/ModelAPI_ResultBody.h +++ b/src/ModelAPI/ModelAPI_ResultBody.h @@ -11,16 +11,16 @@ #include /**\class ModelAPI_ResultBody - * \ingroup DataModel - * \brief The body (shape) result of a feature. - * - * Provides a shape that may be displayed in the viewer. - * May provide really huge results, so, working with this kind - * of result must be optimized. - */ +* \ingroup DataModel +* \brief The body (shape) result of a feature. +* +* Provides a shape that may be displayed in the viewer. +* May provide really huge results, so, working with this kind +* of result must be optimized. +*/ class ModelAPI_ResultBody : public ModelAPI_Result { - public: +public: /// Returns the group identifier of this result virtual std::string groupName() { @@ -44,7 +44,28 @@ class ModelAPI_ResultBody : public ModelAPI_Result { } - protected: + /// Records the subshape newShape which was generated during a topological construction. + /// As an example, consider the case of a face generated in construction of a box. + virtual void generated( + const boost::shared_ptr& theNewShape, const int theTag = 1) = 0; + + /// Records the shape newShape which was generated from the shape oldShape during a topological + /// construction. As an example, consider the case of a face generated from an edge in + /// construction of a prism. + virtual void generated(const boost::shared_ptr& theOldShape, + const boost::shared_ptr& theNewShape, const int theTag = 1) = 0; + + /// Records the shape newShape which is a modification of the shape oldShape. + /// As an example, consider the case of a face split or merged in a Boolean operation. + virtual void modified(const boost::shared_ptr& theOldShape, + const boost::shared_ptr& theNewShape, const int theTag = 1) = 0; + + /// Records the shape oldShape which was deleted from the current label. + /// As an example, consider the case of a face removed by a Boolean operation. + virtual void deleted( + const boost::shared_ptr& theOldShape, const int theTag = 1) = 0; + +protected: /// Use plugin manager for features creation: this method is /// defined here only for SWIG-wrapping ModelAPI_ResultBody() diff --git a/src/ModelAPI/ModelAPI_Session.cpp b/src/ModelAPI/ModelAPI_Session.cpp index 565dd13d3..137f8f8a5 100644 --- a/src/ModelAPI/ModelAPI_Session.cpp +++ b/src/ModelAPI/ModelAPI_Session.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include -- 2.39.2