diff --git a/Framework/Geometry/inc/MantidGeometry/Objects/Object.h b/Framework/Geometry/inc/MantidGeometry/Objects/Object.h
index 5e6aa5dec3dcde95d7d24275df50745f409b0b69..97c0c13077352be8fae2e659d6f43279611a73ed 100644
--- a/Framework/Geometry/inc/MantidGeometry/Objects/Object.h
+++ b/Framework/Geometry/inc/MantidGeometry/Objects/Object.h
@@ -175,6 +175,15 @@ private:
   int checkSurfaceValid(const Kernel::V3D &, const Kernel::V3D &) const;
   BoundingBox m_boundingBox; ///< Object's bounding box
 
+  /// Calculate bounding box using Rule system
+  void calcBoundingBoxByRule();
+
+  /// Calculate bounding box using object's vertices
+  void calcBoundingBoxByVertices();
+
+  /// Calculate bounding box using object's geometric data
+  void calcBoundingBoxByGeometry();
+
   // -- DEPRECATED --
   mutable double AABBxMax,  ///< xmax of Axis aligned bounding box cache
       AABByMax,             ///< ymax of Axis aligned bounding box cache
diff --git a/Framework/Geometry/src/Objects/Object.cpp b/Framework/Geometry/src/Objects/Object.cpp
index fb8ee6505d826c299cf45a75b080f3fe6ae004b6..ae398802e3c6df39f017bca2769b04ca909ef4b2 100644
--- a/Framework/Geometry/src/Objects/Object.cpp
+++ b/Framework/Geometry/src/Objects/Object.cpp
@@ -1465,49 +1465,231 @@ double Object::ConeSolidAngle(const V3D &observer,
 
 /**
 * Returns an axis-aligned bounding box that will fit the shape
-* @returns A shared pointer to a bounding box for this shape.
+* @returns A reference to a bounding box for this shape.
 */
 const BoundingBox &Object::getBoundingBox() const {
   // This member function is const given that from a user's perspective it is
-  // perfecly reasonable
-  // to call it on a const object. We need to call a non-const function in
-  // places to update the cache,
-  // which is where the const_cast comes in to play.
+  // perfectly reasonable to call it on a const object. We need to call a
+  // non-const function in places to update the cache, which is where the
+  // const_cast comes into play.
 
+  // If we don't know the extent of the object, the bounding box doesn't mean
+  // anything
   if (!TopRule) {
-    // If we don't know the extent of the object, the bounding box doesn't mean
-    // anything
     const_cast<Object *>(this)->setNullBoundingBox();
-  } else if (m_boundingBox.isNull()) {
-    // First up, construct the trial set of elements from the object's bounding
-    // box
-    const double big(1e10);
-    double minX(-big), maxX(big), minY(-big), maxY(big), minZ(-big), maxZ(big);
-    TopRule->getBoundingBox(maxX, maxY, maxZ, minX, minY, minZ);
-    // If the object is not axis aligned then the bounding box will be poor, in
-    // particular the minima are left at the trial start so return
-    // a null object here
-    if (minX < -100 || maxX > 100 || minY < -100 || maxY > 100 || minZ < -100 ||
-        maxZ > 100) {
-      // std::cerr << this->getName() << '(' << minX << ',' << maxX << ") (" <<
-      // minY << ',' << maxY << ") (" << minZ << ',' << maxZ << ")\n";
-      minX = -100;
-      maxX = 100;
-      minY = -100;
-      maxY = 100;
-      minZ = -100;
-      maxZ = 100;
+    return m_boundingBox;
+  }
+
+  // We have a bounding box already, so just return it
+  if (m_boundingBox.isNonNull())
+    return m_boundingBox;
+
+  // Try to calculate using Rule method first
+  const_cast<Object *>(this)->calcBoundingBoxByRule();
+  if (m_boundingBox.isNonNull())
+    return m_boundingBox;
+
+  // Rule method failed; Try geometric method
+  const_cast<Object *>(this)->calcBoundingBoxByGeometry();
+  if (m_boundingBox.isNonNull())
+    return m_boundingBox;
+
+  // Geometric method failed; try to calculate by vertices
+  const_cast<Object *>(this)->calcBoundingBoxByVertices();
+  if (m_boundingBox.isNonNull())
+    return m_boundingBox;
+
+  // All options failed; give up
+  // Set to a large box so that a) we don't keep trying to calculate a box
+  // every time this is called and b) to serve as a visual indicator that
+  // something went wrong.
+  const_cast<Object *>(this)
+      ->defineBoundingBox(100, 100, 100, -100, -100, -100);
+  return m_boundingBox;
+}
+
+/**
+ * Attempts to calculate bounding box using Rule system.
+ *
+ * Stores result in bounding box cache if successful. Will only work for shapes
+ * that consist entirely of axis-aligned surfaces and a few special cases (such
+ * as Spheres).
+ */
+void Object::calcBoundingBoxByRule() {
+  // Must have a top rule for this to work
+  if (!TopRule)
+    return;
+
+  // Set up some unreasonable values that will be refined
+  const double huge(1e10);
+  const double big(1e4);
+  double minX(-huge), minY(-huge), minZ(-huge);
+  double maxX(huge), maxY(huge), maxZ(huge);
+
+  // Try to use the Rule system to derive the box
+  TopRule->getBoundingBox(maxX, maxY, maxZ, minX, minY, minZ);
+
+  // Check whether values are reasonable now. Rule system will fail to produce
+  // a reasonable box if the shape is not axis-aligned.
+  if (minX > -big && maxX < big && minY > -big && maxY < big && minZ > -big &&
+      maxZ < big && minX <= maxX && minY <= maxY && minZ <= maxZ) {
+    // Values make sense, cache and return bounding box
+    defineBoundingBox(maxX, maxY, maxZ, minX, minY, minZ);
+  }
+}
+
+/**
+ * Attempts to calculate bounding box using vertex array.
+ *
+ * Stores result in bounding box cache if successful. Will only work for shapes
+ * that have handlers capable of providing a vertex mesh.
+ *
+ * @see GeometryHandler::canTriangulate()
+ */
+void Object::calcBoundingBoxByVertices() {
+  // Grab vertex information
+  auto vertCount = this->NumberOfPoints();
+  auto vertArray = this->getTriangleVertices();
+
+  if (vertCount && vertArray) {
+    // Unreasonable extents to be overwritten by loop
+    constexpr double huge = 1e10;
+    double minX, maxX, minY, maxY, minZ, maxZ;
+    minX = minY = minZ = huge;
+    maxX = maxY = maxZ = -huge;
+
+    // Loop over all vertices and determine minima and maxima on each axis
+    for (int i = 0; i < vertCount; ++i) {
+      auto vx = vertArray[3 * i + 0];
+      auto vy = vertArray[3 * i + 1];
+      auto vz = vertArray[3 * i + 2];
+
+      minX = std::min(minX, vx);
+      maxX = std::max(maxX, vx);
+      minY = std::min(minY, vy);
+      maxY = std::max(maxY, vy);
+      minZ = std::min(minZ, vz);
+      maxZ = std::max(maxZ, vz);
     }
-    if (minX == -big || minY == -big || minZ == -big) {
-      const_cast<Object *>(this)->setNullBoundingBox();
-    } else {
-      const_cast<Object *>(this)
-          ->defineBoundingBox(maxX, maxY, maxZ, minX, minY, minZ);
+
+    // Store bounding box in cache
+    defineBoundingBox(maxX, maxY, maxZ, minX, minY, minZ);
+  }
+}
+
+/**
+ * Attempts to calculate bounding box using object geometry.
+ *
+ * Stores result in bounding box cache if successful. Will only work for basic
+ * shapes that are handled by GluGeometryHandler.
+ */
+void Object::calcBoundingBoxByGeometry() {
+  // Must have a GeometryHandler for this to work
+  if (!handle)
+    return;
+
+  // Extent of bounding box
+  double minX, maxX, minY, maxY, minZ, maxZ;
+
+  // Shape geometry data
+  int type(0);
+  std::vector<Kernel::V3D> vectors;
+  double radius;
+  double height;
+
+  // Will only work for shapes handled by GluGeometryHandler
+  handle->GetObjectGeom(type, vectors, radius, height);
+
+  // Type of shape is given as a simple integer
+  switch (type) {
+  case 1: // CUBOID
+  {
+    // Points as defined in IDF XML
+    auto &lfb = vectors[0]; // Left-Front-Bottom
+    auto &lft = vectors[1]; // Left-Front-Top
+    auto &lbb = vectors[2]; // Left-Back-Bottom
+    auto &rfb = vectors[3]; // Right-Front-Bottom
+
+    // Calculate and add missing corner points to vectors
+    auto lbt = lft + (lbb - lfb); // Left-Back-Top
+    auto rft = rfb + (lft - lfb); // Right-Front-Top
+    auto rbb = lbb + (rfb - lfb); // Right-Back-Bottom
+    auto rbt = rbb + (rft - rfb); // Right-Back-Top
+
+    vectors.push_back(lbt);
+    vectors.push_back(rft);
+    vectors.push_back(rbb);
+    vectors.push_back(rbt);
+
+    // Unreasonable extents to be replaced by first loop cycle
+    constexpr double huge = 1e10;
+    minX = minY = minZ = huge;
+    maxX = maxY = maxZ = -huge;
+
+    // Loop over all corner points to find minima and maxima on each axis
+    for (auto iter = vectors.cbegin(); iter != vectors.cend(); ++iter) {
+      minX = std::min(minX, iter->X());
+      maxX = std::max(maxX, iter->X());
+      minY = std::min(minY, iter->Y());
+      maxY = std::max(maxY, iter->Y());
+      minZ = std::min(minZ, iter->Z());
+      maxZ = std::max(maxZ, iter->Z());
     }
-  } else {
+  } break;
+
+  case 3: // CYLINDER
+  case 5: // SEGMENTED_CYLINDER
+  {
+    // Center-point of base and normalized axis based on IDF XML
+    auto &base = vectors[0];
+    auto &axis = vectors[1];
+    auto top = base + (axis * height); // Center-point of other end
+
+    // How much of the radius must be considered for each axis
+    // (If this ever becomes a performance issue, you could use just the radius
+    // for a quick approx that is still guaranteed to fully contain the shape)
+    volatile auto rx = radius * sqrt(pow(axis.Y(), 2) + pow(axis.Z(), 2));
+    volatile auto ry = radius * sqrt(pow(axis.X(), 2) + pow(axis.Z(), 2));
+    volatile auto rz = radius * sqrt(pow(axis.X(), 2) + pow(axis.Y(), 2));
+
+    // The bounding box is drawn around the base and top center-points,
+    // then expanded in order to account for the radius
+    minX = std::min(base.X(), top.X()) - rx;
+    maxX = std::max(base.X(), top.X()) + rx;
+    minY = std::min(base.Y(), top.Y()) - ry;
+    maxY = std::max(base.Y(), top.Y()) + ry;
+    minZ = std::min(base.Z(), top.Z()) - rz;
+    maxZ = std::max(base.Z(), top.Z()) + rz;
+  } break;
+
+  case 4: // CONE
+  {
+    auto &tip = vectors[0];            // Tip-point of cone
+    auto &axis = vectors[1];           // Normalized axis
+    auto base = tip + (axis * height); // Center of base
+
+    // How much of the radius must be considered for each axis
+    // (If this ever becomes a performance issue, you could use just the radius
+    // for a quick approx that is still guaranteed to fully contain the shape)
+    auto rx = radius * sqrt(pow(axis.Y(), 2) + pow(axis.Z(), 2));
+    auto ry = radius * sqrt(pow(axis.X(), 2) + pow(axis.Z(), 2));
+    auto rz = radius * sqrt(pow(axis.X(), 2) + pow(axis.Y(), 2));
+
+    // For a cone, the adjustment is only applied to the base
+    minX = std::min(tip.X(), base.X() - rx);
+    maxX = std::max(tip.X(), base.X() + rx);
+    minY = std::min(tip.Y(), base.Y() - ry);
+    maxY = std::max(tip.Y(), base.Y() + ry);
+    minZ = std::min(tip.Z(), base.Z() - rz);
+    maxZ = std::max(tip.Z(), base.Z() + rz);
+  } break;
+
+  default:  // Invalid (0, -1) or SPHERE (2) which should be handled by Rules
+    return; // Don't store bounding box
   }
 
-  return m_boundingBox;
+  // Store bounding box in cache
+  defineBoundingBox(maxX, maxY, maxZ, minX, minY, minZ);
 }
 
 /**
diff --git a/Framework/Geometry/test/ObjectTest.h b/Framework/Geometry/test/ObjectTest.h
index dbbe51e152a2028da22940d91154f2834a337688..bd84da02d1e0dac2a3a7f97d33d24dc489bdb3af 100644
--- a/Framework/Geometry/test/ObjectTest.h
+++ b/Framework/Geometry/test/ObjectTest.h
@@ -616,12 +616,11 @@ public:
     TS_ASSERT_DELTA(pt.Y(), -0.1414213562373, 1e-6);
     TS_ASSERT_DELTA(pt.Z(), 0.0, 1e-6);
     planes.clear();
-    // This test fails to find a point in object, as object not on a principle
-    // axis
-    // and getBoundingBox does not give a useful result in this case.
+    // This test used to fail to find a point in object, as object not on a
+    // principle axis and getBoundingBox did not give a useful result in this
+    // case. Framework has now been updated to support this automatically.
     // Object is unit cube located at +-0.5 in x but centred on z=y=-1.606.. and
-    // rotated 45deg
-    // to these two axes
+    // rotated 45deg to these two axes
     planes.push_back("p 1 0 0 -0.5");
     planes.push_back("p 1 0 0 0.5");
     planes.push_back("p 0  .70710678118 .70710678118 -2");
@@ -629,7 +628,7 @@ public:
     planes.push_back("p 0 -.70710678118 .70710678118 -0.5");
     planes.push_back("p 0 -.70710678118 .70710678118 0.5");
     Object_sptr F = createCuboid(planes);
-    TS_ASSERT_EQUALS(F->getPointInObject(pt), 0);
+    TS_ASSERT_EQUALS(F->getPointInObject(pt), 1); // This now succeeds
     // Test use of defineBoundingBox to explictly set the bounding box, when the
     // automatic method fails
     F->defineBoundingBox(0.5, -1 / (2.0 * sqrt(2.0)), -1.0 / (2.0 * sqrt(2.0)),
diff --git a/docs/source/concepts/HowToDefineGeometricShape.rst b/docs/source/concepts/HowToDefineGeometricShape.rst
index b70b96b0003b1a3befe406dc494d2af58658b3ca..978f285ece9735ec4fc4adad6f354e73182c8b6e 100644
--- a/docs/source/concepts/HowToDefineGeometricShape.rst
+++ b/docs/source/concepts/HowToDefineGeometricShape.rst
@@ -58,15 +58,15 @@ plane. Hence, when planning to use
 should be defined such that the positive y-axis is considered to be up,
 the x-axis the width, and the z-axis the depth of the shape.
 
-To be aware off
----------------
+To be aware of
+--------------
 
 When defining a shape you have complete freedom to define it with
 respect to whatever coordinate system you like. However, we have a least
 the following recommendation
 
 -  The origin of coordinate system of a shape is used for calculating
-   the L2 distances. Therefore at least for any TOF instruments where
+   the L2 distances. Therefore, at least for any TOF instruments where
    you care about L2 distances, the origin should be chosen to be at the
    position on your detector shape that is best used for calculation the
    L2 distance
@@ -150,6 +150,7 @@ Cylinder
 
    XMLcylinderDescription.png‎
 
+
 Infinite cylinder
 ~~~~~~~~~~~~~~~~~
 
@@ -161,6 +162,7 @@ Infinite cylinder
         <radius val="1" />
       </infinite-cylinder>
 
+
 Slice of cylinder ring
 ~~~~~~~~~~~~~~~~~~~~~~
 
@@ -181,8 +183,6 @@ the part of this shape facing the sample is flat and looks like this:
 
    XMLsliceCylinderRingDescription.png
 
-For this shape you may find it useful to specify a
-:ref:`Bounding-Box <Bounding-Box>`.
 
 Cone
 ~~~~
@@ -201,6 +201,7 @@ Cone
 
    XMLconeDescription.png
 
+
 Infinite cone
 ~~~~~~~~~~~~~
 
@@ -266,6 +267,7 @@ x-axis). The origin is assumed to be the centre of this front surface,
 which has dimensions 200mm along y and 20mm along z. The depth of this
 cuboid is taken to be 1mm (along x).
 
+
 Hexahedron
 ~~~~~~~~~~
 
@@ -288,8 +290,6 @@ Hexahedron
 
    XMLhexahedronDescription.png
 
-For this shape you may find it useful to specify a
-:ref:`Bounding-Box <Bounding-Box>`.
 
 Tapered Guide
 ~~~~~~~~~~~~~
@@ -315,24 +315,30 @@ axis runs from the start aperture to the end aperture. "Height" is along
 the y-axis and "width" runs along the x-axis, before the application of
 the "axis" rotation.
 
-For this shape you may find it useful to specify a
-:ref:`Bounding-Box <Bounding-Box>`.
 
 .. _Bounding-Box:
 
 Bounding-Box
 ------------
 
-When a geometric shape is rendered in the MantidPlot instrument viewer a
-bounding box is automatically created for each geometric shape. This
-works well for shapes such as cylinders and cuboids. However, for more
-complex shapes and combined shapes the library used for the
-visualization sometimes struggle, which can results in your instrument
-being viewed artificially very small (and you have to zoom in for a long
-time to see your instrument) and often in this context that the
-visualization axes does not display properly. For such cases this can be
-fixed by explicitly adding a bounding-box using the notation
-demonstrated below
+When a geometric shape is rendered in the MantidPlot instrument viewer, Mantid 
+will attempt to automatically construct an axis-aligned bounding box for every 
+geometric shape that does not have one yet. Well-defined bounding boxes are 
+required by many features of Mantid, from correctly rendering the instrument 
+to performing calculations in various algorithms.
+
+The automatically calculated bounding boxes can generally be relied upon and 
+are usually ideal. However, if the automatic calculation fails to produce a 
+reasonable bounding box, or if performance becomes an issue with particularly
+complex shapes, you have the option of adding a manually pre-calculated 
+bounding box.
+
+A typical symptom of the automatic calculation creating an incorrect bounding
+box is your instrument appearing very small when viewed (forcing you to zoom 
+in for a long time to see it). In such cases, the axis visualizations also 
+tend to not display properly.
+
+A custom bounding-box can be added to shapes using the following notation:
 
 .. code-block:: xml
 
@@ -360,4 +366,5 @@ demonstrated below
 Note for the best effect this bounding box should be enclosing the shape
 as tight as possible.
 
+
 .. categories:: Concepts