diff --git a/src/Poly/Poly_Triangulation.cxx b/src/Poly/Poly_Triangulation.cxx
index b367b5a37d..ae7ed0df2e 100644
--- a/src/Poly/Poly_Triangulation.cxx
+++ b/src/Poly/Poly_Triangulation.cxx
@@ -29,26 +29,59 @@ IMPLEMENT_STANDARD_RTTIEXT (Poly_Triangulation, Standard_Transient)
 //function : Poly_Triangulation
 //purpose  : 
 //=======================================================================
-Poly_Triangulation::Poly_Triangulation(const Standard_Integer theNbNodes,
-                                       const Standard_Integer theNbTriangles,
-                                       const Standard_Boolean theHasUVNodes)
-: myDeflection(0),
-  myNodes     (1, theNbNodes),
-  myTriangles (1, theNbTriangles)
+Poly_Triangulation::Poly_Triangulation()
+: myCachedMinMax (NULL),
+  myDeflection   (0)
 {
-  if (theHasUVNodes) myUVNodes = new TColgp_HArray1OfPnt2d(1, theNbNodes);
 }
 
 //=======================================================================
 //function : Poly_Triangulation
 //purpose  : 
 //=======================================================================
+Poly_Triangulation::Poly_Triangulation(const Standard_Integer theNbNodes,
+                                       const Standard_Integer theNbTriangles,
+                                       const Standard_Boolean theHasUVNodes)
+: myCachedMinMax (NULL),
+  myDeflection   (0),
+  myNodes        (1, theNbNodes),
+  myTriangles    (1, theNbTriangles)
+{
+  if (theHasUVNodes) myUVNodes = new TColgp_HArray1OfPnt2d(1, theNbNodes);
+}
 
+//=======================================================================
+//function : Poly_Triangulation
+//purpose  :
+//=======================================================================
+Poly_Triangulation::Poly_Triangulation(const Standard_Integer theNbNodes,
+                                       const Standard_Integer theNbTriangles,
+                                       const Standard_Boolean theHasUVNodes,
+                                       const Standard_Boolean theHasNormals)
+: myDeflection(0),
+  myNodes     (1, theNbNodes),
+  myTriangles (1, theNbTriangles)
+{
+  if (theHasUVNodes)
+  {
+    myUVNodes = new TColgp_HArray1OfPnt2d(1, theNbNodes);
+  }
+  if (theHasNormals)
+  {
+    myNormals = new TShort_HArray1OfShortReal(1, theNbNodes * 3);
+  }
+}
+
+//=======================================================================
+//function : Poly_Triangulation
+//purpose  :
+//=======================================================================
 Poly_Triangulation::Poly_Triangulation(const TColgp_Array1OfPnt&    theNodes,
                                        const Poly_Array1OfTriangle& theTriangles)
-: myDeflection(0),
-  myNodes     (1, theNodes.Length()),
-  myTriangles (1, theTriangles.Length())
+: myCachedMinMax (NULL),
+  myDeflection   (0),
+  myNodes        (1, theNodes.Length()),
+  myTriangles    (1, theTriangles.Length())
 {
   myNodes = theNodes;
   myTriangles = theTriangles;
@@ -62,9 +95,10 @@ Poly_Triangulation::Poly_Triangulation(const TColgp_Array1OfPnt&    theNodes,
 Poly_Triangulation::Poly_Triangulation(const TColgp_Array1OfPnt&    theNodes,
                                        const TColgp_Array1OfPnt2d&  theUVNodes,
                                        const Poly_Array1OfTriangle& theTriangles)
-: myDeflection(0),
-  myNodes     (1, theNodes.Length()),
-  myTriangles (1, theTriangles.Length())
+: myCachedMinMax (NULL),
+  myDeflection   (0),
+  myNodes        (1, theNodes.Length()),
+  myTriangles    (1, theTriangles.Length())
 {
   myNodes = theNodes;
   myTriangles = theTriangles;
@@ -72,6 +106,15 @@ Poly_Triangulation::Poly_Triangulation(const TColgp_Array1OfPnt&    theNodes,
   myUVNodes->ChangeArray1() = theUVNodes;
 }
 
+//=======================================================================
+//function : ~Poly_Triangulation
+//purpose  :
+//=======================================================================
+Poly_Triangulation::~Poly_Triangulation()
+{
+  delete myCachedMinMax;
+}
+
 //=======================================================================
 //function : Copy
 //purpose  : 
@@ -79,16 +122,7 @@ Poly_Triangulation::Poly_Triangulation(const TColgp_Array1OfPnt&    theNodes,
 
 Handle(Poly_Triangulation) Poly_Triangulation::Copy() const
 {
-  Handle(Poly_Triangulation) aCopy;
-  if (HasUVNodes())
-    aCopy = new Poly_Triangulation(Nodes(), UVNodes(), Triangles());
-  else
-    aCopy = new Poly_Triangulation(Nodes(), Triangles());
-  aCopy->Deflection(myDeflection);
-  if (HasNormals())
-    aCopy->myNormals = new TShort_HArray1OfShortReal(myNormals->Array1());
-
-  return aCopy;
+  return new Poly_Triangulation (this);
 }
 
 //=======================================================================
@@ -97,10 +131,12 @@ Handle(Poly_Triangulation) Poly_Triangulation::Copy() const
 //=======================================================================
 
 Poly_Triangulation::Poly_Triangulation (const Handle(Poly_Triangulation)& theTriangulation)
-: myDeflection ( theTriangulation->myDeflection ),
+: myCachedMinMax(NULL),
+  myDeflection(theTriangulation->myDeflection),
   myNodes(theTriangulation->Nodes()),
   myTriangles(theTriangulation->Triangles())
 {
+  SetCachedMinMax (theTriangulation->CachedMinMax());
   if (theTriangulation->HasUVNodes())
   {
     myUVNodes = new TColgp_HArray1OfPnt2d(theTriangulation->myUVNodes->Array1());
@@ -328,3 +364,94 @@ void Poly_Triangulation::DumpJson (Standard_OStream& theOStream, Standard_Intege
     OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNormals->Size())
   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myTriangles.Size())
 }
+
+// =======================================================================
+// function : CachedMinMax
+// purpose  :
+// =======================================================================
+const Bnd_Box& Poly_Triangulation::CachedMinMax() const
+{
+  static const Bnd_Box anEmptyBox;
+  return (myCachedMinMax == NULL) ? anEmptyBox : *myCachedMinMax;
+}
+
+// =======================================================================
+// function : SetCachedMinMax
+// purpose  :
+// =======================================================================
+void Poly_Triangulation::SetCachedMinMax (const Bnd_Box& theBox)
+{
+  if (theBox.IsVoid())
+  {
+    unsetCachedMinMax();
+    return;
+  }
+  if (myCachedMinMax == NULL)
+  {
+    myCachedMinMax = new Bnd_Box();
+  }
+  *myCachedMinMax = theBox;
+}
+
+// =======================================================================
+// function : unsetCachedMinMax
+// purpose  :
+// =======================================================================
+void Poly_Triangulation::unsetCachedMinMax()
+{
+  if (myCachedMinMax != NULL)
+  {
+    delete myCachedMinMax;
+    myCachedMinMax = NULL;
+  }
+}
+
+// =======================================================================
+// function : MinMax
+// purpose  :
+// =======================================================================
+Standard_Boolean Poly_Triangulation::MinMax (Bnd_Box& theBox, const gp_Trsf& theTrsf, const bool theIsAccurate) const
+{
+  Bnd_Box aBox;
+  if (HasCachedMinMax() &&
+      (!HasGeometry() || !theIsAccurate ||
+       theTrsf.Form() == gp_Identity || theTrsf.Form() == gp_Translation ||
+       theTrsf.Form() == gp_PntMirror || theTrsf.Form() == gp_Scale))
+  {
+    aBox = myCachedMinMax->Transformed (theTrsf);
+  }
+  else
+  {
+    aBox = computeBoundingBox (theTrsf);
+  }
+  if (aBox.IsVoid())
+  {
+    return Standard_False;
+  }
+  theBox.Add (aBox);
+  return Standard_True;
+}
+
+// =======================================================================
+// function : computeBoundingBox
+// purpose  :
+// =======================================================================
+Bnd_Box Poly_Triangulation::computeBoundingBox (const gp_Trsf& theTrsf) const
+{
+  Bnd_Box aBox;
+  if (theTrsf.Form() == gp_Identity)
+  {
+    for (Standard_Integer aNodeIdx = 1; aNodeIdx <= NbNodes(); aNodeIdx++)
+    {
+      aBox.Add (myNodes[aNodeIdx]);
+    }
+  }
+  else
+  {
+    for (Standard_Integer aNodeIdx = 1; aNodeIdx <= NbNodes(); aNodeIdx++)
+    {
+      aBox.Add (myNodes[aNodeIdx].Transformed (theTrsf));
+    }
+  }
+  return aBox;
+}
diff --git a/src/Poly/Poly_Triangulation.hxx b/src/Poly/Poly_Triangulation.hxx
index 0465962bba..8808209d1f 100644
--- a/src/Poly/Poly_Triangulation.hxx
+++ b/src/Poly/Poly_Triangulation.hxx
@@ -17,6 +17,7 @@
 #ifndef _Poly_Triangulation_HeaderFile
 #define _Poly_Triangulation_HeaderFile
 
+#include <Bnd_Box.hxx>
 #include <Standard.hxx>
 #include <Standard_DefineHandle.hxx>
 #include <Standard_Real.hxx>
@@ -68,6 +69,9 @@ public:
 
   DEFINE_STANDARD_RTTIEXT(Poly_Triangulation, Standard_Transient)
 
+  //! Constructs an empty triangulation.
+  Standard_EXPORT Poly_Triangulation();
+
   //! Constructs a triangulation from a set of triangles. The
   //! triangulation is initialized without a triangle or a node, but capable of
   //! containing nbNodes nodes, and nbTriangles
@@ -76,6 +80,17 @@ public:
   //! enable a 2D representation).
   Standard_EXPORT Poly_Triangulation(const Standard_Integer nbNodes, const Standard_Integer nbTriangles, const Standard_Boolean UVNodes);
 
+  //! Constructs a triangulation from a set of triangles.
+  //! The triangulation is initialized without a triangle or a node,
+  //! but capable of containing nbNodes nodes, and nbTriangles triangles.
+  //! Here the UVNodes flag indicates whether 2D nodes will be associated with 3D ones,
+  //! (i.e. to enable a 2D representation).
+  //! Here the hasNormals flag indicates whether normals will be given and associated with nodes.
+  Standard_EXPORT Poly_Triangulation(const Standard_Integer nbNodes,
+                                     const Standard_Integer nbTriangles,
+                                     const Standard_Boolean UVNodes,
+                                     const Standard_Boolean hasNormals);
+
   //! Constructs a triangulation from a set of triangles. The
   //! triangulation is initialized with 3D points from Nodes and triangles
   //! from Triangles.
@@ -90,6 +105,9 @@ public:
   //! constructed triangulation.
   Standard_EXPORT Poly_Triangulation(const TColgp_Array1OfPnt& Nodes, const TColgp_Array1OfPnt2d& UVNodes, const Poly_Array1OfTriangle& Triangles);
 
+  //! Destructor
+  Standard_EXPORT virtual ~Poly_Triangulation();
+
   //! Creates full copy of current triangulation
   Standard_EXPORT virtual Handle(Poly_Triangulation) Copy() const;
 
@@ -106,6 +124,9 @@ public:
   //! Deallocates the UV nodes.
   Standard_EXPORT void RemoveUVNodes();
 
+  //! Returns TRUE if triangulation has some geometry.
+  virtual Standard_Boolean HasGeometry() const { return !myNodes.IsEmpty() && !myTriangles.IsEmpty(); }
+
   //! Returns the number of nodes for this triangulation.
   Standard_Integer NbNodes() const { return myNodes.Length(); }
 
@@ -196,11 +217,54 @@ public:
   Standard_EXPORT void SetNormal (const Standard_Integer theIndex,
                                   const gp_Dir&          theNormal);
 
+  //! Returns cached min - max range of triangulation data,
+  //! which is VOID by default (e.g, no cached information).
+  Standard_EXPORT const Bnd_Box& CachedMinMax() const;
+
+  //! Sets a cached min - max range of this triangulation.
+  //! The bounding box should exactly match actual range of triangulation data
+  //! without a gap or transformation, or otherwise undefined behavior will be observed.
+  //! Passing a VOID range invalidates the cache.
+  Standard_EXPORT void SetCachedMinMax (const Bnd_Box& theBox);
+
+  //! Returns TRUE if there is some cached min - max range of this triangulation.
+  Standard_EXPORT Standard_Boolean HasCachedMinMax() const { return myCachedMinMax != NULL; }
+
+  //! Updates cached min - max range of this triangulation with bounding box of nodal data.
+  void UpdateCachedMinMax()
+  {
+    Bnd_Box aBox;
+    MinMax (aBox, gp_Trsf(), true);
+    SetCachedMinMax (aBox);
+  }
+
+  //! Extends the passed box with bounding box of this triangulation.
+  //! Uses cached min - max range when available and:
+  //! - input transformation theTrsf has no rotation part;
+  //! - theIsAccurate is set to FALSE;
+  //! - no triangulation data available (e.g. it is deferred and not loaded).
+  //! @param theBox [in] [out] bounding box to extend by this triangulation
+  //! @param theTrsf [in] optional transformation
+  //! @param theIsAccurate [in] when FALSE, allows using a cached min - max range of this triangulation
+  //!                           even for non-identity transformation.
+  //! @return FALSE if there is no any data to extend the passed box (no both triangulation and cached min - max range).
+  Standard_EXPORT Standard_Boolean MinMax (Bnd_Box& theBox, const gp_Trsf& theTrsf, const bool theIsAccurate = false) const;
+
   //! Dumps the content of me into the stream
   Standard_EXPORT virtual void DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth = -1) const;
 
 protected:
 
+  //! Clears cached min - max range saved previously.
+  Standard_EXPORT void unsetCachedMinMax();
+
+  //! Calculates bounding box of nodal data.
+  //! @param theTrsf [in] optional transformation.
+  Standard_EXPORT virtual Bnd_Box computeBoundingBox (const gp_Trsf& theTrsf) const;
+
+protected:
+
+  Bnd_Box*                           myCachedMinMax;
   Standard_Real                      myDeflection;
   TColgp_Array1OfPnt                 myNodes;
   Handle(TColgp_HArray1OfPnt2d)      myUVNodes;