--- /dev/null
+// Created on: 2017-04-21
+// Created by: Alexander Bobkov
+// Copyright (c) 2017 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <BRepTools_History.hxx>
+
+#include <TopExp.hxx>
+#include <TopTools_IndexedMapOfShape.hxx>
+
+// Implement the OCCT RTTI for the type.
+IMPLEMENT_STANDARD_RTTIEXT(BRepTools_History, Standard_Transient)
+
+namespace
+{
+
+//==============================================================================
+//function : add
+//purpose : Adds the elements of the list to the map.
+//==============================================================================
+void add(TopTools_MapOfShape& theMap, const TopTools_ListOfShape& theList)
+{
+ for (TopTools_ListOfShape::Iterator aSIt(theList); aSIt.More(); aSIt.Next())
+ {
+ theMap.Add(aSIt.Value());
+ }
+}
+
+//==============================================================================
+//function : add
+//purpose : Adds the elements of the collection to the list.
+//==============================================================================
+template<typename TCollection>
+void add(TopTools_ListOfShape& theList, const TCollection& theCollection)
+{
+ for (typename TCollection::Iterator aSIt(theCollection);
+ aSIt.More(); aSIt.Next())
+ {
+ theList.Append(aSIt.Value());
+ }
+}
+
+}
+
+//==============================================================================
+//function : AddGenerated
+//purpose :
+//==============================================================================
+void BRepTools_History::AddGenerated(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theGenerated)
+{
+ if (!prepareGenerated(theInitial, theGenerated))
+ {
+ return;
+ }
+
+ TopTools_ListOfShape* aGenerations =
+ myShapeToGenerated.ChangeSeek(theInitial);
+ if (aGenerations == NULL)
+ {
+ aGenerations = myShapeToGenerated.Bound(theInitial, TopTools_ListOfShape());
+ }
+
+ Standard_ASSERT_VOID(!aGenerations->Contains(theGenerated),
+ "Error: a duplicated generation of a shape.");
+
+ aGenerations->Append(theGenerated);
+}
+
+//==============================================================================
+//function : AddModified
+//purpose :
+//==============================================================================
+void BRepTools_History::AddModified(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theModified)
+{
+ if (!prepareModified(theInitial, theModified))
+ {
+ return;
+ }
+
+ TopTools_ListOfShape* aModifications =
+ myShapeToModified.ChangeSeek(theInitial);
+ if (aModifications == NULL)
+ {
+ aModifications =
+ myShapeToModified.Bound(theInitial, TopTools_ListOfShape());
+ }
+
+ Standard_ASSERT_VOID(!aModifications->Contains(theModified),
+ "Error: a duplicated modification of a shape.");
+
+ aModifications->Append(theModified);
+}
+
+//==============================================================================
+//function : Remove
+//purpose :
+//==============================================================================
+void BRepTools_History::Remove(const TopoDS_Shape& theRemoved)
+{
+ // Apply the limitations.
+ Standard_ASSERT_RETURN(IsSupportedType(theRemoved), myMsgUnsupportedType,);
+
+ if (myShapeToGenerated.UnBind(theRemoved))
+ {
+ Standard_ASSERT_INVOKE_(, myMsgGeneratedAndRemoved);
+ }
+
+ if (myShapeToModified.UnBind(theRemoved))
+ {
+ Standard_ASSERT_INVOKE_(, myMsgModifiedAndRemoved);
+ }
+
+ //
+ myRemoved.Add(theRemoved);
+}
+
+//==============================================================================
+//function : ReplaceGenerated
+//purpose :
+//==============================================================================
+void BRepTools_History::ReplaceGenerated(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theGenerated)
+{
+ if (!prepareGenerated(theInitial, theGenerated))
+ {
+ return;
+ }
+
+ TopTools_ListOfShape* aGenerations =
+ myShapeToGenerated.Bound(theInitial, TopTools_ListOfShape());
+ aGenerations->Append(theGenerated);
+}
+
+//==============================================================================
+//function : ReplaceModified
+//purpose :
+//==============================================================================
+void BRepTools_History::ReplaceModified(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theModified)
+{
+ if (!prepareModified(theInitial, theModified))
+ {
+ return;
+ }
+
+ TopTools_ListOfShape* aModifications =
+ myShapeToModified.Bound(theInitial, TopTools_ListOfShape());
+ aModifications->Append(theModified);
+}
+
+//==============================================================================
+//function : Generated
+//purpose :
+//==============================================================================
+const TopTools_ListOfShape& BRepTools_History::Generated(
+ const TopoDS_Shape& theInitial) const
+{
+ // Apply the limitations.
+ Standard_ASSERT_RETURN(theInitial.IsNull() || IsSupportedType(theInitial),
+ myMsgUnsupportedType, emptyList());
+
+ //
+ const TopTools_ListOfShape* aGenerations =
+ myShapeToGenerated.Seek(theInitial);
+ return (aGenerations != NULL) ? *aGenerations : emptyList();
+}
+
+//==============================================================================
+//function : Modified
+//purpose :
+//==============================================================================
+const TopTools_ListOfShape& BRepTools_History::Modified(
+ const TopoDS_Shape& theInitial) const
+{
+ // Apply the limitations.
+ Standard_ASSERT_RETURN(IsSupportedType(theInitial),
+ myMsgUnsupportedType, emptyList());
+
+ //
+ const TopTools_ListOfShape* aModifications =
+ myShapeToModified.Seek(theInitial);
+ return (aModifications != NULL) ? *aModifications : emptyList();
+}
+
+//==============================================================================
+//function : IsRemoved
+//purpose :
+//==============================================================================
+Standard_Boolean BRepTools_History::IsRemoved(
+ const TopoDS_Shape& theInitial) const
+{
+ // Apply the limitations.
+ Standard_ASSERT_RETURN(IsSupportedType(theInitial),
+ myMsgUnsupportedType, Standard_False);
+
+ //
+ return myRemoved.Contains(theInitial);
+}
+
+//==============================================================================
+//function : Merge
+//purpose :
+//==============================================================================
+void BRepTools_History::Merge(const Handle(BRepTools_History)& theHistory23)
+{
+ // Propagate R23 directly and M23 and G23 fully to M12 and G12.
+ // Remember the propagated shapes.
+ TopTools_DataMapOfShapeListOfShape* aS1ToGAndM[] =
+ {&myShapeToGenerated, &myShapeToModified};
+ TopTools_MapOfShape aRPropagated;
+ {
+ // Propagate R23, M23 and G23 to M12 and G12 directly.
+ // Remember the propagated shapes.
+ TopTools_MapOfShape aMAndGPropagated;
+ for (Standard_Integer aI = 0; aI < 2; ++aI)
+ {
+ for (TopTools_DataMapOfShapeListOfShape::Iterator aMIt1(*aS1ToGAndM[aI]);
+ aMIt1.More(); aMIt1.Next())
+ {
+ TopTools_ListOfShape& aL12 = aMIt1.ChangeValue();
+ TopTools_MapOfShape aAdditions[2]; // The G and M additions.
+ for (TopTools_ListOfShape::Iterator aSIt2(aL12); aSIt2.More();)
+ {
+ const TopoDS_Shape& aS2 = aSIt2.Value();
+ if (theHistory23->IsRemoved(aS2))
+ {
+ aL12.Remove(aSIt2);
+ aRPropagated.Add(aS2);
+ }
+ else
+ {
+ if (theHistory23->myShapeToGenerated.IsBound(aS2))
+ {
+ add(aAdditions[0], theHistory23->myShapeToGenerated(aS2));
+ aMAndGPropagated.Add(aS2);
+ }
+
+ if (theHistory23->myShapeToModified.IsBound(aS2))
+ {
+ add(aAdditions[aI], theHistory23->myShapeToModified(aS2));
+ aMAndGPropagated.Add(aS2);
+
+ aL12.Remove(aSIt2);
+ }
+ else
+ {
+ aSIt2.Next();
+ }
+ }
+ }
+
+ add(aL12, aAdditions[aI]);
+ if (aI != 0 && !aAdditions[0].IsEmpty())
+ {
+ const TopoDS_Shape& aS1 = aMIt1.Key();
+ TopTools_ListOfShape* aGAndM = aS1ToGAndM[0]->ChangeSeek(aS1);
+ if (aGAndM == NULL)
+ {
+ aGAndM = aS1ToGAndM[0]->Bound(aS1, TopTools_ListOfShape());
+ }
+
+ add(*aGAndM, aAdditions[0]);
+ }
+ }
+ }
+
+ // Propagate M23 and G23 to M12 and G12 sequentially.
+ const TopTools_DataMapOfShapeListOfShape* aS2ToGAndM[] =
+ {&theHistory23->myShapeToGenerated, &theHistory23->myShapeToModified};
+ for (Standard_Integer aI = 0; aI < 2; ++aI)
+ {
+ for (TopTools_DataMapOfShapeListOfShape::Iterator aMIt2(*aS2ToGAndM[aI]);
+ aMIt2.More(); aMIt2.Next())
+ {
+ const TopoDS_Shape& aS2 = aMIt2.Key();
+ if (!aMAndGPropagated.Contains(aS2))
+ {
+ if (!aS1ToGAndM[aI]->IsBound(aS2))
+ {
+ aS1ToGAndM[aI]->Bind(aS2, TopTools_ListOfShape());
+ }
+
+ TopTools_ListOfShape aM2 = aMIt2.Value();
+ ((*aS1ToGAndM[aI])(aS2)).Append(aM2);
+ }
+ }
+ }
+ }
+
+ // Unbound the empty M12 and G12.
+ for (Standard_Integer aI = 0; aI < 2; ++aI)
+ {
+ for (TopTools_DataMapOfShapeListOfShape::Iterator aMIt1(*aS1ToGAndM[aI]);
+ aMIt1.More();)
+ {
+ const TopoDS_Shape& aS1 = aMIt1.Key();
+ const TopTools_ListOfShape& aL12 = aMIt1.Value();
+ aMIt1.Next();
+ if (aL12.IsEmpty())
+ {
+ aS1ToGAndM[aI]->UnBind(aS1);
+ }
+ }
+ }
+
+ // Propagate R23 to R12 sequentially.
+ for (TopTools_MapOfShape::Iterator aRIt23(theHistory23->myRemoved);
+ aRIt23.More(); aRIt23.Next())
+ {
+ const TopoDS_Shape& aS2 = aRIt23.Value();
+ if (!aRPropagated.Contains(aS2) &&
+ !myShapeToModified.IsBound(aS2) &&
+ !myShapeToGenerated.IsBound(aS2))
+ {
+ myRemoved.Add(aS2);
+ }
+ }
+}
+
+//==============================================================================
+//function : prepareGenerated
+//purpose :
+//==============================================================================
+Standard_Boolean BRepTools_History::prepareGenerated(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theGenerated)
+{
+ Standard_ASSERT_RETURN(theInitial.IsNull() ||
+ IsSupportedType(theInitial), myMsgUnsupportedType, Standard_False);
+
+ if (myRemoved.Remove(theInitial))
+ {
+ Standard_ASSERT_INVOKE_(, myMsgGeneratedAndRemoved);
+ }
+
+ if (myShapeToModified.IsBound(theInitial) &&
+ myShapeToModified(theInitial).Remove(theGenerated))
+ {
+ Standard_ASSERT_INVOKE_(, myMsgGeneratedAndModified);
+ }
+
+ return Standard_True;
+}
+
+//==============================================================================
+//function : prepareModified
+//purpose :
+//==============================================================================
+Standard_Boolean BRepTools_History::prepareModified(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theModified)
+{
+ Standard_ASSERT_RETURN(IsSupportedType(theInitial),
+ myMsgUnsupportedType, Standard_False);
+
+ if (myRemoved.Remove(theInitial))
+ {
+ Standard_ASSERT_INVOKE_(, myMsgModifiedAndRemoved);
+ }
+
+ if (myShapeToGenerated.IsBound(theInitial) &&
+ myShapeToGenerated(theInitial).Remove(theModified))
+ {
+ Standard_ASSERT_INVOKE_(, myMsgGeneratedAndModified);
+ }
+
+ return Standard_True;
+}
+
+//==============================================================================
+//data : myEmptyList
+//purpose :
+//==============================================================================
+const TopTools_ListOfShape BRepTools_History::myEmptyList;
+
+//==============================================================================
+//function : emptyList
+//purpose :
+//==============================================================================
+const TopTools_ListOfShape& BRepTools_History::emptyList()
+{
+ return myEmptyList;
+}
+
+//==============================================================================
+//data : myMsgUnsupportedType
+//purpose :
+//==============================================================================
+const char* BRepTools_History::myMsgUnsupportedType =
+ "Error: unsupported shape type.";
+
+//==============================================================================
+//data : myMsgGeneratedAndRemoved
+//purpose :
+//==============================================================================
+const char* BRepTools_History::myMsgGeneratedAndRemoved =
+ "Error: a shape is generated and removed simultaneously.";
+
+//==============================================================================
+//data : myMsgModifiedAndRemoved
+//purpose :
+//==============================================================================
+const char* BRepTools_History::myMsgModifiedAndRemoved =
+ "Error: a shape is modified and removed simultaneously.";
+
+//==============================================================================
+//data : myMsgGeneratedAndModified
+//purpose :
+//==============================================================================
+const char* BRepTools_History::myMsgGeneratedAndModified =
+ "Error: a shape is generated and modified "
+ "from the same shape simultaneously.";
--- /dev/null
+// Created on: 2017-04-21
+// Created by: Alexander Bobkov
+// Copyright (c) 2017 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#ifndef _BRepTools_History_HeaderFile
+#define _BRepTools_History_HeaderFile
+
+#include <NCollection_Handle.hxx>
+#include <TopTools_DataMapOfShapeListOfShape.hxx>
+#include <TopTools_MapOfShape.hxx>
+
+class BRepTools_History;
+DEFINE_STANDARD_HANDLE(BRepTools_History, Standard_Transient)
+
+//! The history keeps the following relations between the input shapes
+//! (S1, ..., Sm) and output shapes (T1, ..., Tn):
+//! 1) an output shape Tj is generated from an input shape Si: Tj <= G(Si);
+//! 2) a output shape Tj is modified from an input shape Si: Tj <= M(Si);
+//! 3) an input shape (Si) is removed: R(Si) == 1.
+//!
+//! The relations are kept only for shapes of types vertex, edge, face, and
+//! solid.
+//!
+//! The last relation means that:
+//! 1) shape Si is not an output shape and
+//! 2) no any shape is generated or modified (produced) from shape Si:
+//! R(Si) == 1 ==> Si != Tj, G(Si) == 0, M(Si) == 0.
+//!
+//! No any shape could be generated and modified from the same shape
+//! simultaneously: sets G(Si) and M(Si) are not intersected
+//! (G(Si) ^ M(Si) == 0).
+//!
+//! Each output shape should be:
+//! 1) an input shape or
+//! 2) generated or modified from an input shape (even generated from the
+//! implicit null shape if necessary):
+//! Tj == Si V (exists Si that Tj <= G(Si) U M(Si)).
+//!
+//! Recommendations to choose between relations 'generated' and 'modified':
+//! 1) a shape is generated from input shapes if it dimension is greater or
+//! smaller than the dimensions of the input shapes;
+//! 2) a shape is generated from input shapes if these shapes are also output
+//! shapes;
+//! 3) a shape is generated from input shapes of the same dimension if it is
+//! produced by joining shapes generated from these shapes;
+//! 4) a shape is modified from an input shape if it replaces the input shape by
+//! changes of the location, the tolerance, the bounds of the parametrical
+//! space (the faces for a solid), the parametrization and/or by applying of
+//! an approximation;
+//! 5) a shape is modified from input shapes of the same dimension if it is
+//! produced by joining shapes modified from these shapes.
+//!
+//! Two sequential histories:
+//! - one history (H12) of shapes S1, ..., Sm to shapes T1, ..., Tn and
+//! - another history (H23) of shapes T1, ..., Tn to shapes Q1, ..., Ql
+//! could be merged to the single history (H13) of shapes S1, ..., Sm to shapes
+//! Q1, ..., Ql.
+//!
+//! During the merge:
+//! 1) if shape Tj is generated from shape Si then each shape generated or
+//! modified from shape Tj is considered as a shape generated from shape Si
+//! among shapes Q1, ..., Ql:
+//! Tj <= G12(Si), Qk <= G23(Tj) U M23(Tj) ==> Qk <= G13(Si).
+//! 2) if shape Tj is modified from shape Si, shape Qk is generated from shape
+//! Tj then shape Qk is considered as a shape generated from shape Si among
+//! shapes Q1, ..., Ql:
+//! Tj <= M12(Si), Qk <= G23(Tj) ==> Qk <= G13(Si);
+//! 3) if shape Tj is modified from shape Si, shape Qk is modified from shape
+//! Tj then shape Qk is considered as a shape modified from shape Si among
+//! shapes Q1, ..., Ql:
+//! Tj <= M12(Si), Qk <= M23(Tj) ==> Qk <= M13(Si);
+class BRepTools_History: public Standard_Transient
+{
+public:
+
+ //! The types of the historical relations.
+ enum TRelationType
+ {
+ TRelationType_Removed,
+ TRelationType_Generated,
+ TRelationType_Modified
+ };
+
+public:
+
+ //! Returns 'true' if the type of the shape is supported by the history.
+ static Standard_Boolean IsSupportedType(const TopoDS_Shape& theShape)
+ {
+ const TopAbs_ShapeEnum aType = theShape.ShapeType();
+ return aType == TopAbs_VERTEX || aType == TopAbs_EDGE ||
+ aType == TopAbs_FACE || aType == TopAbs_SOLID;
+ }
+
+public: //! Methods to set the history.
+
+ //! Set the second shape as generated one from the first shape.
+ Standard_EXPORT void AddGenerated(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theGenerated);
+
+ //! Set the second shape as modified one from the first shape.
+ Standard_EXPORT void AddModified(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theModified);
+
+ //! Set the shape as removed one.
+ Standard_EXPORT void Remove(const TopoDS_Shape& theRemoved);
+
+ //! Set the second shape as the only generated one from the first one.
+ Standard_EXPORT void ReplaceGenerated(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theGenerated);
+
+ //! Set the second shape as the only modified one from the first one.
+ Standard_EXPORT void ReplaceModified(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theModified);
+
+ //! Clears the history.
+ void Clear()
+ {
+ myShapeToModified.Clear();
+ myShapeToGenerated.Clear();
+ myRemoved.Clear();
+ }
+
+public: //! Methods to read the history.
+
+ //! Returns all shapes generated from the shape.
+ Standard_EXPORT
+ const TopTools_ListOfShape& Generated(const TopoDS_Shape& theInitial) const;
+
+ //! Returns all shapes modified from the shape.
+ Standard_EXPORT
+ const TopTools_ListOfShape& Modified(const TopoDS_Shape& theInitial) const;
+
+ //! Returns 'true' if the shape is removed.
+ Standard_EXPORT
+ Standard_Boolean IsRemoved(const TopoDS_Shape& theInitial) const;
+
+public: //! A method to merge a next history to this history.
+
+ //! Merges the next history to this history.
+ Standard_EXPORT void Merge(const Handle(BRepTools_History)& theHistory23);
+
+public:
+
+ //! Define the OCCT RTTI for the type.
+ DEFINE_STANDARD_RTTIEXT(BRepTools_History, Standard_Transient)
+
+private:
+ //! Prepares the shapes generated from the first shape to set the second one
+ //! as generated one from the first one by the addition or the replacement.
+ //! Returns 'true' on success.
+ Standard_Boolean prepareGenerated(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theGenerated);
+
+ //! Prepares the shapes modified from the first shape to set the second one
+ //! as modified one from the first one by the addition or the replacement.
+ //! Returns 'true' on success.
+ Standard_Boolean prepareModified(
+ const TopoDS_Shape& theInitial, const TopoDS_Shape& theModified);
+
+private: //! Data to keep the history.
+
+ //! Maps each input shape to all shapes modified from it.
+ //! If an input shape is not bound to the map then
+ //! there is no shapes modified from the shape.
+ //! No any shape should be mapped to an empty list.
+ TopTools_DataMapOfShapeListOfShape myShapeToModified;
+
+ //! Maps each input shape to all shapes generated from it.
+ //! If an input shape is not bound to the map then
+ //! there is no shapes generated from the shape.
+ //! No any shape should be mapped to an empty list.
+ TopTools_DataMapOfShapeListOfShape myShapeToGenerated;
+
+ TopTools_MapOfShape myRemoved; //!< The removed shapes.
+
+private: //! Auxiliary members to read the history.
+
+ //! An auxiliary empty list.
+ static const TopTools_ListOfShape myEmptyList;
+
+ //! A method to export the auxiliary list.
+ Standard_EXPORT static const TopTools_ListOfShape& emptyList();
+
+private:
+
+ //! Auxiliary messages.
+ static const char* myMsgUnsupportedType;
+ static const char* myMsgGeneratedAndRemoved;
+ static const char* myMsgModifiedAndRemoved;
+ static const char* myMsgGeneratedAndModified;
+};
+
+#endif // _BRepTools_History_HeaderFile