/* -*- mia-c++  -*-
 *
 * This file is part of MIA - a toolbox for medical image analysis 
 * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
 *
 * MIA is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MIA; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <mia/internal/plugintester.hh>
#include <mia/3d/cost/ncc.hh>
#include <mia/core/nccsum.hh>

using namespace NS; 
using namespace mia; 




BOOST_AUTO_TEST_CASE( test_ncc_zero ) 
{
        C3DBounds size(4,4,4); 
        auto ncc = BOOST_TEST_create_from_plugin<CNCC3DImageCostPlugin>("ncc");
        
        C3DFImage a(size); 
        C3DFImage b(size); 
        
        auto ia = a.begin_range(C3DBounds::_0, size); 
        auto ib = b.begin_range(C3DBounds::_0, size); 
        auto ea = a.end_range(C3DBounds::_0, size); 

        while (ia != ea) {
                *ia = ia.pos().x + ia.pos().y + ia.pos().z; 
                *ib = 2* *ia; 
                ++ib; ++ia; 
        }

        ncc->set_reference(b); 
        BOOST_CHECK_SMALL(ncc->value(b), 1e-7); 

        BOOST_CHECK_SMALL(ncc->value(a), 1e-7); 
        
        
}

BOOST_AUTO_TEST_CASE( test_ncc_nonzero ) 
{
        C3DBounds size(4,4,4); 
        auto ncc = BOOST_TEST_create_from_plugin<CNCC3DImageCostPlugin>("ncc");
        
        C3DFImage a(size); 
        C3DFImage b(size); 

       
        auto ia = a.begin_range(C3DBounds::_0, size); 
        auto ib = b.begin_range(C3DBounds::_0, size); 
        auto ea = a.end_range(C3DBounds::_0, size); 

        NCCSums sum; 

        while (ia != ea) {
                *ia = ia.pos().x + ia.pos().y + ia.pos().z; 
                *ib = ia.pos().x + ia.pos().y * ia.pos().z; 
                sum.add(*ia, *ib); 
                ++ib; ++ia; 
        }

        ncc->set_reference(b); 
        BOOST_CHECK_CLOSE(ncc->value(a), sum.value(), 0.1); 
        
        C3DFVectorfield grad(size); 

        BOOST_CHECK_CLOSE(ncc->evaluate_force(a, grad), sum.value(), 0.01);


	auto ag = get_gradient(a); 
	
	auto iag = ag.begin(); 
	auto ia2 = a.begin(); 
	auto ib2 = b.begin(); 
	auto iforce = grad.begin(); 
	auto eforce = grad.end(); 

	auto gs = sum.get_grad_helper().second; 
	while (iforce != eforce) {
		auto expect = *iag * gs.get_gradient_scale(*ia2, *ib2); 
		BOOST_CHECK_CLOSE(iforce->x, expect.x, 0.01); 
		BOOST_CHECK_CLOSE(iforce->y, expect.y, 0.01); 
		BOOST_CHECK_CLOSE(iforce->z, expect.z, 0.01); 
		++iag; ++ia2; ++ib2; ++iforce;
	}
}


