function [result_viewer, result, post_result] = gtReconstructTestCase(test_data, det_index, use_ODF)

    if (~exist('det_index', 'var') || isempty(det_index))
        det_index = 1;
    end

    if (~exist('use_ODF', 'var') || isempty(use_ODF))
        use_ODF = 'none';
    end

    rec_opts = gtReconstruct6DGetParamenters(test_data.parameters);

    if (~isfield(test_data, 'gv'))
        test_data.gv.dm = gtDefDmvol2Gvdm(test_data.dmvol);
    end
    gvdm = test_data.gv.dm(:, test_data.gv.used_ind);
    if (~isfield(test_data, 'intvol'))
        size_int_vol = [ ...
            size(test_data.dmvol, 1), ...
            size(test_data.dmvol, 2), ...
            size(test_data.dmvol, 3) ];
        test_data.intvol = ones(size_int_vol, 'like', test_data.dmvol);
    end
    gvpow = test_data.intvol(test_data.gv.used_ind);

    gtGetMaxDisorientation(gvdm, [], 'diameter_average');
    gtGetMaxDisorientation(gvdm, [], 'diameter_zero');

%     f = figure();
%     ax = axes('parent', f);
%     hold(ax, 'on')
%     scatter3(ax, gvdm(1, 1:10:end)', gvdm(2, 1:10:end)', gvdm(3, 1:10:end)', 20);

    sampler = GtOrientationSampling(test_data.parameters, test_data.grain,'detector_index', det_index);
    sampler.make_simple_grid_estim_ODF('cubic', rec_opts.grid_edge, false, 1); %rec_opts.ospace_oversize);

%     scatter3(ax, sampler.R_vectors{1}(:, 1), sampler.R_vectors{1}(:, 2), sampler.R_vectors{1}(:, 3), 20, 'r');
%     drawnow();

    ospace_bb = [min(gvdm, [], 2), max(gvdm, [], 2)];
    sampler.make_res_even_simple_grid('cubic', rec_opts.grid_edge, ospace_bb, rec_opts.ospace_oversize);

%     scatter3(ax, sampler.R_vectors{1}(:, 1), sampler.R_vectors{1}(:, 2), sampler.R_vectors{1}(:, 3), 20, 'g');
%     hold(ax, 'off')
%     drawnow();

    if (rec_opts.ospace_super_sampling > 1)
        sampler.make_supersampling_simple_grid([1 2 3], rec_opts.ospace_super_sampling);
    end

    switch (use_ODF)
        case 'none'
            odf = [];
        case 'theo'
%             odf = gtGetODFFromGvdm(gvdm, sampler.lattice.gr, gvpow, 'nearest');
            odf = gtGetODFFromGvdm(gvdm, sampler.lattice.gr, gvpow, 'linear');
    end

    [algo, good_or] = gtReconstruct6DLaunchAlgorithm(sampler, rec_opts, ...
        test_data.parameters, 'det_index', det_index, 'ODF', odf);

    vols = algo.getCurrentSolution();

    or_sizes = sampler.get_orientation_sampling_size();

    [avg_R_vecs, avg_R_vecs_int, stddev_R_vecs] = sampler.getAverageOrientations(vols, good_or);
    avg_R_vec = sampler.getAverageOrientation(vols, good_or);
    s_g_odf = reshape(sampler.getODF(vols, good_or), or_sizes{1});

    vol_size = size(avg_R_vecs_int);
    shift = gtFwdSimComputeVolumeShifts(test_data.grain.proj(det_index), test_data.parameters, vol_size);

    [kam, gam] = gtDefComputeKernelAverageMisorientation(avg_R_vecs, avg_R_vecs_int);
    [igm, gos] = gtDefComputeIntraGranularMisorientation(avg_R_vecs, avg_R_vecs_int, 'R_vector', test_data.grain.R_vector);

    % Restoring initial volume size (depending on the rounding)
    if (rec_opts.volume_downscaling > 1)
        fprintf('Expanding volumes..')
        c = tic();
        avg_R_vecs_int = gtMathsUpsampleVolume(avg_R_vecs_int, rec_opts.volume_downscaling);
        avg_R_vecs = gtMathsUpsampleVolume(avg_R_vecs, rec_opts.volume_downscaling);
        stddev_R_vecs = gtMathsUpsampleVolume(stddev_R_vecs, rec_opts.volume_downscaling);
        kam = gtMathsUpsampleVolume(kam, rec_opts.volume_downscaling);
        igm = gtMathsUpsampleVolume(igm, rec_opts.volume_downscaling);

        vols = gtMathsUpsampleVolume(vols, rec_opts.volume_downscaling);
        fprintf('\b\b: Done (%f seconds).\n', toc(c))
    end

    result = gt6DAssembleResult(test_data, sampler, vols);

    result.ODF6D = struct( ...
        'voxels_avg_R_vectors', {avg_R_vecs}, ...
        'intensity', {avg_R_vecs_int}, ...
        'shift', {shift}, ...
        'R_vectors', {sampler.get_R_vectors()}, ...
        'voxels_stddev_R_vectors', {stddev_R_vecs}, ...
        'single_grain_ODF', {s_g_odf}, ...
        'single_grain_avg_R_vector', {avg_R_vec}, ...
        'kernel_average_misorientation', {kam}, ...
        'intra_granular_misorientation', {igm} );

    post_result = gt6DPostProcessOrientationSpread(test_data, result, true);

    [proj_blobs, proj_spots] = algo.getProjectionOfCurrentSolution();

    post_result.ODF6D = struct( ...
        'orientation_volumes', {vols}, ...
        'fwd_projected_blobs', {proj_blobs}, ...
        'fwd_projected_spots', {proj_spots}, ...
        'grain_average_misorientation', {gam}, ...
        'grain_orientation_spread', {gos}, ...
        'compute_statistics', {algo.get_statistics()} );

    result_viewer = GtOrientationResultView(test_data, result, post_result, ...
        'f_title', sprintf('Result Browser: algo "%s", det_id %d, ODF: "%s"', ...
        test_data.parameters.rec.grains.algorithm, det_index, use_ODF));
end