<commit_before>#include "chr/path/FollowablePath3D.h"

#include "chr/utils/Utils.h"
#include "chr/math/Utils.h"

using namespace std;
using namespace chr;

namespace chr
{
  namespace path
  {
    FollowablePath3D::FollowablePath3D(size_t capacity)
    {
      if (capacity > 0)
      {
        points.reserve(capacity);
        lengths.reserve(capacity);
      }
    }

    void FollowablePath3D::clear()
    {
      points.clear();
      lengths.clear();
    }

    void FollowablePath3D::reserve(size_t n)
    {
      points.reserve(n);
      lengths.reserve(n);
    }

    size_t FollowablePath3D::size() const
    {
      return points.size();
    }

    bool FollowablePath3D::empty() const
    {
      return points.empty();
    }

    float FollowablePath3D::getLength() const
    {
      if (!empty())
      {
        return lengths.back();
      }
      else
      {
        return 0;
      }
    }

    const vector<FollowablePath3D::Point>& FollowablePath3D::getPoints() const
    {
      return points;
    }

    const vector<float>& FollowablePath3D::getLengths() const
    {
      return lengths;
    }

    FollowablePath3D& FollowablePath3D::setMode(Mode mode)
    {
      this->mode = mode;
      return *this;
    }

    FollowablePath3D& FollowablePath3D::setSampling(Sampling sampling)
    {
      this->sampling = sampling;
      return *this;
    }

    FollowablePath3D& FollowablePath3D::begin()
    {
      points.clear();
      lengths.clear();

      return *this;
    }

    FollowablePath3D& FollowablePath3D::end(bool close)
    {
      auto end = size();

      if (close)
      {
        if ((end > 2) && (points.front().position != points.back().position))
        {
          add(points.front().position, points.front().left);
          points.back().forward = points.front().forward;

          return *this;
        }
      }

      if (end > 1)
      {
        points[end - 1].forward = points[end - 2].forward;
      }

      return *this;
    }

    FollowablePath3D& FollowablePath3D::add(const glm::vec3 &position, const glm::vec3 &left)
    {
      if (!empty())
      {
        auto delta = position - points.back().position;
        auto length = glm::length(delta); // ASSERT: length > EPSILON

        lengths.push_back(lengths.back() + length);
        points.back().forward = delta / length;
      }
      else
      {
        lengths.push_back(0);
      }

      points.emplace_back(position, left);
      return *this;
    }

    glm::quat FollowablePath3D::offsetToQuat(float offset, float sampleSize) const
    {
      float length = getLength();

      if (length > 0)
      {
        if ((sampling != SAMPLING_NONE) && (sampleSize > 0))
        {
          float offset0, offset1;

          if (mode == MODE_MODULO)
          {
            offset = math::boundf(offset, length);
          }

          if (mode == MODE_LOOP)
          {
            offset0 = math::boundf(offset - sampleSize * 0.5f, length);
            offset1 = math::boundf(offset + sampleSize * 0.5f, length);

            if (offset1 < offset0)
            {
              std::swap(offset0, offset1);
            }
          }
          else
          {
            offset0 = offset - sampleSize * 0.5f;
            offset1 = offset + sampleSize * 0.5f;
          }

          if (mode == MODE_BOUNDED)
          {
            if ((offset1 <= 0) || ((offset0 < 0) && (offset1 > 0)))
            {
              return points.front().toQuat();
            }
            else if ((offset0 >= length) || ((offset1 > length) && (offset0 < length)))
            {
              return points.back().toQuat();
            }
          }

          auto index0 = utils::search(lengths, offset0, 1, size());
          auto index1 = utils::search(lengths, offset1, 1, size());

          if (index1 < index0)
          {
            return points[index0].toQuat();
          }
          else if (index0 > index1)
          {
            return points[index1].toQuat();
          }<commit_msg>FollowablePath3D: ON PAR WITH RECENT CHANGES IN FollowablePath2D<commit_after>#include "chr/path/FollowablePath3D.h"

#include "chr/utils/Utils.h"
#include "chr/math/Utils.h"

using namespace std;
using namespace chr;

namespace chr
{
  namespace path
  {
    FollowablePath3D::FollowablePath3D(size_t capacity)
    {
      if (capacity > 0)
      {
        points.reserve(capacity);
        lengths.reserve(capacity);
      }
    }

    void FollowablePath3D::clear()
    {
      points.clear();
      lengths.clear();
    }

    void FollowablePath3D::reserve(size_t n)
    {
      points.reserve(n);
      lengths.reserve(n);
    }

    size_t FollowablePath3D::size() const
    {
      return points.size();
    }

    bool FollowablePath3D::empty() const
    {
      return points.empty();
    }

    float FollowablePath3D::getLength() const
    {
      if (!empty())
      {
        return lengths.back();
      }
      else
      {
        return 0;
      }
    }

    const vector<FollowablePath3D::Point>& FollowablePath3D::getPoints() const
    {
      return points;
    }

    const vector<float>& FollowablePath3D::getLengths() const
    {
      return lengths;
    }

    FollowablePath3D& FollowablePath3D::setMode(Mode mode)
    {
      this->mode = mode;
      return *this;
    }

    FollowablePath3D& FollowablePath3D::setSampling(Sampling sampling)
    {
      this->sampling = sampling;
      return *this;
    }

    FollowablePath3D& FollowablePath3D::begin()
    {
      points.clear();
      lengths.clear();

      return *this;
    }

    FollowablePath3D& FollowablePath3D::end(bool close)
    {
      auto end = size();
      bool closed = (end > 2) && (points.front().position == points.back().position);

      if (!closed)
      {
        if (close && (end > 2))
        {
          add(points.front().position, points.front().left);
          points.back().forward = points.front().forward;
        }
        else
        {
          if (end > 1)
          {
            points[end - 1].forward = points[end - 2].forward;
          }
        }
      }

      return *this;
    }

    FollowablePath3D& FollowablePath3D::add(const glm::vec3 &position, const glm::vec3 &left)
    {
      if (!empty())
      {
        auto delta = position - points.back().position;
        auto length = glm::length(delta); // ASSERT: length > EPSILON

        lengths.push_back(lengths.back() + length);
        points.back().forward = delta / length;
      }
      else
      {
        lengths.push_back(0);
      }

      points.emplace_back(position, left);
      return *this;
    }

    glm::quat FollowablePath3D::offsetToQuat(float offset, float sampleSize) const
    {
      float length = getLength();

      if (length > 0)
      {
        if ((sampling != SAMPLING_NONE) && (sampleSize > 0))
        {
          float offset0, offset1;

          if (mode == MODE_MODULO)
          {
            offset = math::boundf(offset, length);
          }

          if (mode == MODE_LOOP)
          {
            offset0 = math::boundf(offset - sampleSize * 0.5f, length);
            offset1 = math::boundf(offset + sampleSize * 0.5f, length);
          }
          else
          {
            offset0 = offset - sampleSize * 0.5f;
            offset1 = offset + sampleSize * 0.5f;
          }

          if (mode == MODE_BOUNDED)
          {
            if ((offset1 <= 0) || ((offset0 < 0) && (offset1 > 0)))
            {
              return points.front().toQuat();
            }
            else if ((offset0 >= length) || ((offset1 > length) && (offset0 < length)))
            {
              return points.back().toQuat();
            }
          }

          auto index0 = utils::search(lengths, offset0, 1, size());
          auto index1 = utils::search(lengths, offset1, 1, size());

          if (index0 == index1)
          {
            return points[index0].toQuat();
          }
{'fraction_non_alphanumeric': 0.12862547288776796, 'fraction_numerical': 0.017654476670870115, 'mean_word_length': 1.75, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3816753', 'n_tokens_mistral': 2518, 'n_tokens_neox': 2437, 'n_words': 480}