/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2023, Individual contributors, see AUTHORS file     |
   | See: https://www.mrpt.org/Authors - All rights reserved.               |
   | Released under BSD License. See: https://www.mrpt.org/License          |
   +------------------------------------------------------------------------+ */

/**
 * samples/poses example.
 * Shows the common PDF and 2D/3D pose manipulation operations.
 */

#include <mrpt/poses/CPoint3D.h>
#include <mrpt/poses/CPointPDFGaussian.h>
#include <mrpt/poses/CPose3D.h>
#include <mrpt/poses/CPoses2DSequence.h>
#include <mrpt/system/CTicTac.h>

#include <iostream>

using namespace mrpt;
using namespace mrpt::poses;
using namespace mrpt::system;
using namespace std;

// ------------------------------------------------------
//				TestPosePDFOperations
// ------------------------------------------------------
void TestPosePDFOperations()
{
	CPointPDFGaussian p1, p2, p;

	/**
	 * Construct the CPointPDFGaussian instances
	 * initialize and pass a mean to the p1, p2 instances and a covariance
	 * matrix. The latter is done by explicitly adding the cov. matrix elemnts
	 */
	p1.mean = CPoint3D(0, -0.12, 0);
	p2.mean = CPoint3D(0, -0.1, 0);

	p1.cov.setZero();
	p1.cov(0, 0) = 0.06f;
	p1.cov(0, 1) = 0.002f;
	p1.cov(1, 0) = 0.002f;
	p1.cov(1, 1) = 0.02f;
	p1.cov(2, 2) = 0.0002f;

	p2.cov.setZero();
	p2.cov(0, 0) = 0.02f;
	p2.cov(0, 1) = -0.004f;
	p2.cov(1, 0) = -0.004f;
	p2.cov(1, 1) = 0.01f;
	p2.cov(2, 2) = 0.0002f;

	// Integral of Product of gaussians:
	CTicTac tictac;
	double v;

	tictac.Tic();
	for (int i = 0; i < 10000; i++)
		v = p1.productIntegralWith(p2);

	printf("Time for computing: %.04fus\n", tictac.Tac() * 1e+6f / 10000);

	printf("product p1,p2 -> %f\n", v);
	printf("product p2,p1 -> %f\n", p2.productIntegralNormalizedWith(p1));

	// Bayesian fusion:
	p.bayesianFusion(p1, p2);
	p.saveToTextFile("BayesFusion.txt");

	cout << "Bayesian fusing of p1 & p2: " << endl;
	cout << " MEAN: " << p.mean << " COV:" << endl << p.cov << endl;
}

// ------------------------------------------------------
//				TestPoseComposition
// ------------------------------------------------------
void TestPoseComposition()
{
	CTicTac tictac;

	// ---------------------------------------------------------------
	/**
	 * CPose3D default constructor method takes the arguments in the
	 * (X, Y, Z, YAW=0, PITCH=0, ROLL=0) format. The angles are optional
	 */
	CPose3D A(0, 0, 0), B(1, 1, 0, 45.0_deg, 0, 0), C;

	C = A - B;

	cout << "A:\n" << A << endl;
	cout << "B:\n" << B << endl;
	cout << "C:\n" << C << endl;

	// ---------------------------------------------------------------
	CPose2D p(0.5f, 0.2f, DEG2RAD(10.0f));

	// stores a sequence of relative, incremental 2D poses
	CPoses2DSequence seq;

	CPose2D a(1, 2, (float)0.0_deg);
	CPose2D b(2, 3, (float)45.0_deg);
	CPose2D D;

	CPose2D x(1, 0, (float)0.0_deg);
	CPose2D y(1, 0, (float)45.0_deg);

	cout << "a= " << a << endl;
	cout << "b= " << b << endl;

	// ------------------------------------------
	tictac.Tic();
	D = a + b;
	printf("%f us\t", tictac.Tac() * 1e6);
	cout << "a+b= " << D << endl;
	// ------------------------------------------
	tictac.Tic();
	D = b - a;
	printf("%f us\t", tictac.Tac() * 1e6);
	cout << "b-a= " << D << endl;
	// ------------------------------------------
	tictac.Tic();
	D = a + (b - a);
	printf("%f us\t", tictac.Tac() * 1e6);
	cout << "a + (b-a)= " << D << endl;
	// ------------------------------------------

	/**
	 * Incrementally update the pose of the "robot".
	 * Appending the pose is equivalent to a position/rotation change with
	 * regards to the body-fixed frame of reference
	 * For more information refer to:
	 * https://reference.mrpt.org/stable/_c_poses2_d_sequence_8h_source.html
	 */
	seq.appendPose(y);
	cout << "last= " << seq.absolutePoseAfterAll() << endl;
	seq.appendPose(y);
	cout << "last= " << seq.absolutePoseAfterAll() << endl;
	seq.appendPose(x);
	cout << "last= " << seq.absolutePoseAfterAll() << endl;

	// play the poses from the beginning using the getPose method
	seq.getPose(0, D);
	cout << "Pose[0] in seq.= " << D << endl;
	seq.getPose(1, D);
	cout << "Pose[1] in seq.= " << D << endl;
	seq.getPose(2, D);
	cout << "Pose[2] in seq.= " << D << endl;
}

// ------------------------------------------------------
//						MAIN
// ------------------------------------------------------
int main()
{
	try
	{
		TestPoseComposition();
		TestPosePDFOperations();

		return 0;
	}
	catch (exception& e)
	{
		cout << "MRPT exception caught: " << e.what() << endl;
		return -1;
	}
}
