/* +------------------------------------------------------------------------+
   |                     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          |
   +------------------------------------------------------------------------+ */

#include "nav-precomp.h"  // Precomp header
//
#include <mrpt/nav/tpspace/CPTG_DiffDrive_CC.h>
#include <mrpt/serialization/CArchive.h>
#include <mrpt/system/os.h>

using namespace mrpt;
using namespace mrpt::nav;
using namespace mrpt::system;

IMPLEMENTS_SERIALIZABLE(
	CPTG_DiffDrive_CC, CParameterizedTrajectoryGenerator, mrpt::nav)

void CPTG_DiffDrive_CC::loadFromConfigFile(
	const mrpt::config::CConfigFileBase& cfg, const std::string& sSection)
{
	CPTG_DiffDrive_CollisionGridBased::loadFromConfigFile(cfg, sSection);

	MRPT_LOAD_CONFIG_VAR_NO_DEFAULT(K, double, cfg, sSection);

	// The constant curvature turning radius used in this PTG:
	R = V_MAX / W_MAX;
}
void CPTG_DiffDrive_CC::saveToConfigFile(
	mrpt::config::CConfigFileBase& cfg, const std::string& sSection) const
{
	MRPT_START
	const int WN = 25, WV = 30;
	CPTG_DiffDrive_CollisionGridBased::saveToConfigFile(cfg, sSection);

	cfg.write(
		sSection, "K", K, WN, WV,
		"K=+1 forward paths; K=-1 for backwards paths.");

	MRPT_END
}

void CPTG_DiffDrive_CC::serializeFrom(
	mrpt::serialization::CArchive& in, uint8_t version)
{
	CPTG_DiffDrive_CollisionGridBased::internal_readFromStream(in);

	switch (version)
	{
		case 0: in >> K; break;
		default: MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(version);
	};
}

uint8_t CPTG_DiffDrive_CC::serializeGetVersion() const { return 0; }
void CPTG_DiffDrive_CC::serializeTo(mrpt::serialization::CArchive& out) const
{
	CPTG_DiffDrive_CollisionGridBased::internal_writeToStream(out);
	out << K;
}

std::string CPTG_DiffDrive_CC::getDescription() const
{
	char str[100];
	os::sprintf(str, 100, "CPTG_DiffDrive_CC,K=%i", (int)K);
	return std::string(str);
}

void CPTG_DiffDrive_CC::ptgDiffDriveSteeringFunction(
	[[maybe_unused]] float alpha, [[maybe_unused]] float t,
	[[maybe_unused]] float x, [[maybe_unused]] float y,
	[[maybe_unused]] float phi, [[maybe_unused]] float& v,
	[[maybe_unused]] float& w) const
{
	float u = fabs(alpha) * 0.5f;  /// 6.0f;

	if (t < u * R / V_MAX)
	{
		// l-
		v = -V_MAX;
		w = W_MAX;
	}
	else if (t < (u + M_PI * 0.5f) * R / V_MAX)
	{
		// l+
		v = V_MAX;
		w = W_MAX;
	}
	else
	{
		// END:
		v = w = 0;
	}

	// Turn in the opposite direction??
	if (alpha < 0) w *= -1;

	v *= K;
	w *= K;
}

bool CPTG_DiffDrive_CC::PTG_IsIntoDomain(double x, double y) const
{
	// Aprox domain: The circle at (0,R):
	return (square(x) + square(fabs(y) - R)) <= R;
}

void CPTG_DiffDrive_CC::loadDefaultParams()
{
	CPTG_DiffDrive_CollisionGridBased::loadDefaultParams();
	K = +1.0;
}
