/* +------------------------------------------------------------------------+
   |                     Mobile Robot Programming Toolkit (MRPT)            |
   |                          https://www.mrpt.org/                         |
   |                                                                        |
   | Copyright (c) 2005-2026, 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 "poses-precomp.h"  // Precompiled headers
//
#include <mrpt/poses/CPoses2DSequence.h>
#include <mrpt/serialization/CArchive.h>

using namespace mrpt;
using namespace mrpt::poses;
using namespace mrpt::math;

IMPLEMENTS_SERIALIZABLE(CPoses2DSequence, CSerializable, mrpt::poses)

size_t CPoses2DSequence::posesCount() { return poses.size(); }
uint8_t CPoses2DSequence::serializeGetVersion() const { return 0; }
void CPoses2DSequence::serializeTo(mrpt::serialization::CArchive& out) const
{
  out.WriteAs<uint32_t>(poses.size());
  for (const auto& p : poses) out << p;
}
void CPoses2DSequence::serializeFrom(mrpt::serialization::CArchive& in, uint8_t version)
{
  switch (version)
  {
    case 0:
    {
      poses.resize(in.ReadAs<uint32_t>());
      for (auto& p : poses) in >> p;
    }
    break;
    default:
      MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(version);
  };
}

/*---------------------------------------------------------------
Reads the stored pose at index "ind", where the first one is 0, the last
"posesCount() - 1"
 ---------------------------------------------------------------*/
void CPoses2DSequence::getPose(unsigned int ind, CPose2D& outPose)
{
  if (ind >= poses.size()) THROW_EXCEPTION("Index out of range!!");

  outPose = poses[ind];
}

/*---------------------------------------------------------------
Changes the stored pose at index "ind", where the first one is 0, the last
"posesCount() - 1"
 ---------------------------------------------------------------*/
void CPoses2DSequence::changePose(unsigned int ind, CPose2D& inPose)
{
  if (ind >= poses.size()) THROW_EXCEPTION("Index out of range!!");

  *((&(poses[ind])) + ind) = inPose;
}

/*---------------------------------------------------------------
  Appends a new pose at the end of sequence. Remember that poses are relative,
 incremental to the last one.
 ---------------------------------------------------------------*/
void CPoses2DSequence::appendPose(CPose2D& newPose) { poses.push_back(newPose); }

/*---------------------------------------------------------------
      Clears the sequence.
 ---------------------------------------------------------------*/
void CPoses2DSequence::clear() { poses.clear(); }
/*---------------------------------------------------------------
 ---------------------------------------------------------------*/
/** Returns the absolute pose of a robot after moving "n" poses, so for "n=0"
 * the origin pose (0,0,0deg) is returned, for "n=1" the first pose is returned,
 * and for "n=posesCount()", the pose
 *  of robot after moving ALL poses is returned, all of them relative to the
 * starting pose.
 */
CPose2D CPoses2DSequence::absolutePoseOf(unsigned int n)
{
  CPose2D ret(0, 0, 0);
  unsigned int i;

  if (n > poses.size()) THROW_EXCEPTION("Index out of range!!");

  for (i = 0; i < n; i++) ret = ret + poses[i];

  return ret;
}

CPose2D CPoses2DSequence::absolutePoseAfterAll() { return absolutePoseOf(posesCount()); }

double CPoses2DSequence::computeTraveledDistanceAfter(size_t n)
{
  double dist = 0;

  if (n > poses.size()) THROW_EXCEPTION("Index out of range!!");

  for (size_t i = 0; i < n; i++) dist += poses[i].norm();

  return dist;
}

double CPoses2DSequence::computeTraveledDistanceAfterAll()
{
  return computeTraveledDistanceAfter(posesCount());
}
