Index: src/sas/sascalc/corfunc/corfunc_calculator.py
===================================================================
--- src/sas/sascalc/corfunc/corfunc_calculator.py	(revision ff11b21937c0657ed4709a35bf3ee586f4e3148c)
+++ src/sas/sascalc/corfunc/corfunc_calculator.py	(revision c72829533b5fef8ae525bccfe32be80c455714df)
@@ -34,5 +34,13 @@
 
         def __call__(self, x):
-            if self._lastx == [] or x.tolist() != self._lastx.tolist():
+            # If input is a single number, evaluate the function at that number
+            # and return a single number
+            if type(x) == float or type(x) == int:
+                return self._smoothed_function(np.array([x]))[0]
+            # If input is a list, and is different to the last input, evaluate
+            # the function at each point. If the input is the same as last time
+            # the function was called, return the result that was calculated
+            # last time instead of explicity evaluating the function again.
+            elif self._lastx == [] or x.tolist() != self._lastx.tolist():
                 self._lasty = self._smoothed_function(x)
                 self._lastx = x
@@ -121,5 +129,5 @@
         extrapolation = Data1D(qs, iqs)
 
-        return params, extrapolation
+        return params, extrapolation, s2
 
     def compute_transform(self, extrapolation, trans_type, background=None,
@@ -131,4 +139,5 @@
         :param background: The background value (if not provided, previously
             calculated value will be used)
+        :param extrap_fn: A callable function representing the extraoplated data
         :param completefn: The function to call when the transform calculation
             is complete`
@@ -144,5 +153,6 @@
         if trans_type == 'fourier':
             self._transform_thread = FourierThread(self._data, extrapolation,
-            background, completefn=completefn, updatefn=updatefn)
+            background, completefn=completefn,
+            updatefn=updatefn)
         elif trans_type == 'hilbert':
             self._transform_thread = HilbertThread(self._data, extrapolation,
Index: src/sas/sascalc/corfunc/transform_thread.py
===================================================================
--- src/sas/sascalc/corfunc/transform_thread.py	(revision d03228e40acd75d47d8dad9f9401dcde8e5a280c)
+++ src/sas/sascalc/corfunc/transform_thread.py	(revision a309667e4e06f5545093db4d49943dab71213a48)
@@ -2,4 +2,5 @@
 from sas.sascalc.dataloader.data_info import Data1D
 from scipy.fftpack import dct
+from scipy.integrate import trapz
 import numpy as np
 from time import sleep
@@ -13,4 +14,11 @@
         self.extrapolation = extrapolated_data
 
+    def check_if_cancelled(self):
+        if self.isquit():
+            self.update("Fourier transform cancelled.")
+            self.complete(transforms=None)
+            return True
+        return False
+
     def compute(self):
         qs = self.extrapolation.x
@@ -19,15 +27,48 @@
         background = self.background
 
+        xs = np.pi*np.arange(len(qs),dtype=np.float32)/(q[1]-q[0])/len(qs)
+
         self.ready(delay=0.0)
-        self.update(msg="Starting Fourier transform.")
+        self.update(msg="Fourier transform in progress.")
         self.ready(delay=0.0)
-        if self.isquit():
-            return
+
+        if self.check_if_cancelled(): return
         try:
-            gamma = dct((iqs-background)*qs**2)
-            gamma = gamma / gamma.max()
-        except:
+            # ----- 1D Correlation Function -----
+            gamma1 = dct((iqs-background)*qs**2)
+            Q = gamma1.max()
+            gamma1 /= Q
+
+            if self.check_if_cancelled(): return
+
+            # ----- 3D Correlation Function -----
+            # gamma3(R) = 1/R int_{0}^{R} gamma1(x) dx
+            # trapz uses the trapezium rule to calculate the integral
+            mask = xs <= 200.0 # Only calculate gamma3 up to x=200 (as this is all that's plotted)
+            gamma3 = [trapz(gamma1[:n], xs[:n])/xs[n-1] for n in range(2, len(xs[mask]) + 1)]
+            gamma3.insert(0, 1.0) # Gamma_3(0) is defined as 1
+            gamma3 = np.array(gamma3)
+
+            if self.check_if_cancelled(): return
+
+            # ----- Interface Distribution function -----
+            idf = dct(-qs**4 * (iqs-background))
+
+            if self.check_if_cancelled(): return
+
+            # Manually calculate IDF(0.0), since scipy DCT tends to give us a
+            # very large negative value.
+            # IDF(x) = int_0^inf q^4 * I(q) * cos(q*x) * dq
+            # => IDF(0) = int_0^inf q^4 * I(q) * dq
+            idf[0] = trapz(-qs**4 * (iqs-background), qs)
+            idf /= Q # Normalise using scattering invariant
+
+        except Exception as e:
+            import logging
+            logger = logging.getLogger(__name__)
+            logger.error(e)
+
             self.update(msg="Fourier transform failed.")
-            self.complete(transform=None)
+            self.complete(transforms=None)
             return
         if self.isquit():
@@ -35,8 +76,11 @@
         self.update(msg="Fourier transform completed.")
 
-        xs = np.pi*np.arange(len(qs),dtype=np.float32)/(q[1]-q[0])/len(qs)
-        transform = Data1D(xs, gamma)
+        transform1 = Data1D(xs, gamma1)
+        transform3 = Data1D(xs[xs <= 200], gamma3)
+        idf = Data1D(xs, idf)
 
-        self.complete(transform=transform)
+        transforms = (transform1, transform3, idf)
+
+        self.complete(transforms=transforms)
 
 class HilbertThread(CalcThread):
@@ -64,3 +108,3 @@
         self.update(msg="Hilbert transform completed.")
 
-        self.complete(transform=None)
+        self.complete(transforms=None)
Index: src/sas/sasgui/perspectives/corfunc/corfunc.py
===================================================================
--- src/sas/sasgui/perspectives/corfunc/corfunc.py	(revision 463e7ffce130ae386f93cd18b87a1120743e88b5)
+++ src/sas/sasgui/perspectives/corfunc/corfunc.py	(revision 9b90bf84a52cb67272ccbed5bac69156a6ca6bc3)
@@ -189,4 +189,13 @@
             # Show the transformation as a curve instead of points
             new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
+        elif label == IDF_LABEL:
+            new_plot.xaxis("{x}", 'A')
+            new_plot.yaxis("{g_1}", '')
+            # Linear scale
+            new_plot.xtransform = 'x'
+            new_plot.ytransform = 'y'
+            group_id = GROUP_ID_IDF
+            # Show IDF as a curve instead of points
+            new_plot.symbol = GUIFRAME_ID.CURVE_SYMBOL_NUM
         new_plot.id = label
         new_plot.name = label
Index: src/sas/sasgui/perspectives/corfunc/corfunc_panel.py
===================================================================
--- src/sas/sasgui/perspectives/corfunc/corfunc_panel.py	(revision 7432acb919f4013119ca918a73350297e0d4c93f)
+++ src/sas/sasgui/perspectives/corfunc/corfunc_panel.py	(revision 9b90bf84a52cb67272ccbed5bac69156a6ca6bc3)
@@ -55,4 +55,7 @@
         self._data = data # The data to be analysed (corrected fr background)
         self._extrapolated_data = None # The extrapolated data set
+        # Callable object of class CorfuncCalculator._Interpolator representing
+        # the extrapolated and interpolated data
+        self._extrapolated_fn = None
         self._transformed_data = None # Fourier trans. of the extrapolated data
         self._calculator = CorfuncCalculator()
@@ -218,5 +221,6 @@
 
         try:
-            params, self._extrapolated_data = self._calculator.compute_extrapolation()
+            params, self._extrapolated_data, self._extrapolated_fn = \
+                self._calculator.compute_extrapolation()
         except Exception as e:
             msg = "Error extrapolating data:\n"
@@ -257,10 +261,10 @@
             StatusEvent(status=msg))
 
-    def transform_complete(self, transform=None):
+    def transform_complete(self, transforms=None):
         """
         Called from FourierThread when calculation has completed
         """
         self._transform_btn.SetLabel("Transform")
-        if transform is None:
+        if transforms is None:
             msg = "Error calculating Transform."
             if self.transform_type == 'hilbert':
@@ -270,9 +274,17 @@
             self._extract_btn.Disable()
             return
-        self._transformed_data = transform
-        import numpy as np
-        plot_x = transform.x[np.where(transform.x <= 200)]
-        plot_y = transform.y[np.where(transform.x <= 200)]
+
+        self._transformed_data = transforms
+        (transform1, transform3, idf) = transforms
+        plot_x = transform1.x[transform1.x <= 200]
+        plot_y = transform1.y[transform1.x <= 200]
         self._manager.show_data(Data1D(plot_x, plot_y), TRANSFORM_LABEL1)
+        # No need to shorten gamma3 as it's only calculated up to x=200
+        self._manager.show_data(transform3, TRANSFORM_LABEL3)
+
+        plot_x = idf.x[idf.x <= 200]
+        plot_y = idf.y[idf.x <= 200]
+        self._manager.show_data(Data1D(plot_x, plot_y), IDF_LABEL)
+
         # Only enable extract params button if a fourier trans. has been done
         if self.transform_type == 'fourier':
@@ -286,5 +298,5 @@
         """
         try:
-            params = self._calculator.extract_parameters(self._transformed_data)
+            params = self._calculator.extract_parameters(self._transformed_data[0])
         except:
             params = None
Index: src/sas/sasgui/perspectives/corfunc/corfunc_state.py
===================================================================
--- src/sas/sasgui/perspectives/corfunc/corfunc_state.py	(revision 7432acb919f4013119ca918a73350297e0d4c93f)
+++ src/sas/sasgui/perspectives/corfunc/corfunc_state.py	(revision 457f7351de0a1b8d55c0422b73cc572a1cbbfc8f)
@@ -59,5 +59,4 @@
         self.q = None
         self.iq = None
-        # TODO: Add extrapolated data and transformed data (when implemented)
 
     def __str__(self):
Index: src/sas/sasgui/perspectives/corfunc/media/corfunc_help.rst
===================================================================
--- src/sas/sasgui/perspectives/corfunc/media/corfunc_help.rst	(revision 1404cce8849b35a676efe8d5fcb1bdbc540f413b)
+++ src/sas/sasgui/perspectives/corfunc/media/corfunc_help.rst	(revision d78b5cb8640ad6951b4ff99f576d1033eaebf0c5)
@@ -10,11 +10,11 @@
 
 This performs a correlation function analysis of one-dimensional
-SAXS/SANS data, or generates a model-independent volume fraction 
+SAXS/SANS data, or generates a model-independent volume fraction
 profile from the SANS from an adsorbed polymer/surfactant layer.
 
-A correlation function may be interpreted in terms of an imaginary rod moving 
-through the structure of the material. Î\ :sub:`1D`\ (R) is the probability that 
-a rod of length R moving through the material has equal electron/neutron scattering 
-length density at either end. Hence a frequently occurring spacing within a structure 
+A correlation function may be interpreted in terms of an imaginary rod moving
+through the structure of the material. Î\ :sub:`1D`\ (R) is the probability that
+a rod of length R moving through the material has equal electron/neutron scattering
+length density at either end. Hence a frequently occurring spacing within a structure
 manifests itself as a peak.
 
@@ -30,5 +30,5 @@
 *  Fourier / Hilbert Transform of the smoothed data to give the correlation
    function / volume fraction profile, respectively
-*  (Optional) Interpretation of the 1D correlation function based on an ideal 
+*  (Optional) Interpretation of the 1D correlation function based on an ideal
    lamellar morphology
 
@@ -74,9 +74,9 @@
    :align: center
 
-   
+
 Smoothing
 ---------
 
-The extrapolated data set consists of the Guinier back-extrapolation from Q~0 
+The extrapolated data set consists of the Guinier back-extrapolation from Q~0
 up to the lowest Q value in the original data, then the original scattering data, and the Porod tail-fit beyond this. The joins between the original data and the Guinier/Porod fits are smoothed using the algorithm below to avoid the formation of ripples in the transformed data.
 
@@ -93,5 +93,5 @@
     h_i = \frac{1}{1 + \frac{(x_i-b)^2}{(x_i-a)^2}}
 
-	
+
 Transform
 ---------
@@ -102,5 +102,5 @@
 If "Fourier" is selected for the transform type, the analysis will perform a
 discrete cosine transform on the extrapolated data in order to calculate the
-correlation function
+1D correlation function:
 
 .. math::
@@ -115,4 +115,10 @@
     \left(n + \frac{1}{2} \right) k \right] } \text{ for } k = 0, 1, \ldots,
     N-1, N
+
+The 3D correlation function is also calculated:
+
+.. math::
+    \Gamma _{3D}(R) = \frac{1}{Q^{*}} \int_{0}^{\infty}I(q) q^{2}
+    \frac{sin(qR)}{qR} dq
 
 Hilbert
@@ -165,8 +171,8 @@
 .. figure:: profile1.png
    :align: center
- 
+
 .. figure:: profile2.png
    :align: center
-   
+
 
 References
@@ -191,5 +197,5 @@
 -----
 Upon sending data for correlation function analysis, it will be plotted (minus
-the background value), along with a *red* bar indicating the *upper end of the 
+the background value), along with a *red* bar indicating the *upper end of the
 low-Q range* (used for back-extrapolation), and 2 *purple* bars indicating the range to be used for forward-extrapolation. These bars may be moved my clicking and
 dragging, or by entering appropriate values in the Q range input boxes.
@@ -221,5 +227,5 @@
     :align: center
 
-	
+
 .. note::
     This help document was last changed by Steve King, 08Oct2016
Index: src/sas/sasgui/perspectives/corfunc/plot_labels.py
===================================================================
--- src/sas/sasgui/perspectives/corfunc/plot_labels.py	(revision 1dc8ec9bbfd72210acd49400626adfb8eb6c3c87)
+++ src/sas/sasgui/perspectives/corfunc/plot_labels.py	(revision 7dda833a648fe9c4be0256b3048be490124ed4a1)
@@ -4,4 +4,7 @@
 
 GROUP_ID_TRANSFORM = r"$\Gamma(x)$"
-TRANSFORM_LABEL1 = r"$\Gamma1(x)$"
-TRANSFORM_LABEL3 = r"$\Gamma3(x)$"
+TRANSFORM_LABEL1 = r"$\Gamma_1(x)$"
+TRANSFORM_LABEL3 = r"$\Gamma_3(x)$"
+
+GROUP_ID_IDF = r"$g_1(x)$"
+IDF_LABEL = r"$g_1(x)$"
