<commit_before>#include "Bezier.h"
#include <other/core/vector/Matrix4x4.h>
#include <other/core/vector/Matrix.h>
#include <other/core/utility/stl.h>
#include <other/core/python/Class.h>
#include <other/core/python/stl.h>
#include <other/core/geometry/polygon.h>
#include <iostream>
namespace other {

using std::cout;
using std::endl;

template<> OTHER_DEFINE_TYPE(Bezier<2>)
template<> OTHER_DEFINE_TYPE(Knot<2>)

static double interpolate(double v0, double v1, double v2, double v3, double t) {
  Vector<real,4> i(v0,v1,v2,v3);
  Matrix<real,4> mx( -1, 3, -3, 1,
                     3, -6, 3, 0,
                     -3,3, 0, 0,
                     1, 0,0, 0);

  Vector<real,4> a = mx*i; // transpose because of legacy constructor
  return a.w + t*(a.z + t*(a.y + t*a.x));
}

template<int d> static Vector<real,d> point(Vector<real,d> v0, Vector<real,d> v1, Vector<real,d> v2, Vector<real,d> v3, double t) {
  Vector<real,d> result;
  for (int i = 0; i < d; i++)
    result[i] = interpolate(v0[i],v1[i],v2[i],v3[i],t);
  return result;
}

template<int d> Tuple<Array<Vector<real,d>>, vector<int>> Bezier<d>::evaluate_core(const InvertibleBox& range, int res) const{
  Array<Vector<real,d>> path;
  vector<int> forced;

  if (knots.size()<=1) return tuple(path,forced);
  Vector<real,d> p1, p2, p3, p4;

  auto it = knots.upper_bound(range.begin);
  auto end = knots.lower_bound(range.end);
  if (end == knots.end()) end--;
  if (it!=knots.begin()) it--;
  OTHER_ASSERT(it!=knots.end() && end!=knots.end());
  while(it!=end){
    //jump across null segment end->beginning for closed
    if(b_closed && it->first == t_max()){
      if(range.end == t_min() || range.end == t_max())
        break;
      it = knots.begin();
    }

    p1 = it->second->pt;
    p2 = it->second->tangent_out;

    it++;
    if(it == knots.end()) it = knots.begin(); // wrap around at end

    p3 = it->second->tangent_in;
    p4 = it->second->pt;

    if ((p4-p2).magnitude() > 1e-8) {
      // first point in this segment
      forced.push_back(path.size());
      path.append(other::point(p1,p2,p3,p4,0));

      for (int j=1;j<res;j++) {
        real t = j/(real)(res); // (0,1)
        path.append(other::point(p1,p2,p3,p4,t));
      }
    }
  }
  // last point
  forced.push_back(path.size());
  path.append(end->second->pt);

  return tuple(path, forced);
}

template<int d> Array<Vector<real,d>> Bezier<d>::evaluate(const InvertibleBox& range, int res) const{
  return evaluate_core(range, res).x;
}

template<int d> real Bezier<d>::arclength(const InvertibleBox& range, int res) const {
  Array<Vector<real,d>> path = evaluate(range,std::max(res, 500));

  // measure the length of the path
  real total_length = 0;
  for (int i = 1; i < (int)path.size(); ++i) {
    total_length += (path[i-1] - path[i]).magnitude();
  }

  return total_length;
}

template<int d> Array<Vector<real,d>> Bezier<d>::alen_evaluate(const InvertibleBox& range, int res) const{
  const bool debug = false;

  if (debug)
    std::cout << "sampling range " << range << " with " << res << " segments." << " bezier range: " << t_range << std::endl;

  auto pathinfo = evaluate_core(range,std::max(10*res, 500));
  Array<Vector<real,d>> const &path = pathinfo.x;
  vector<int> const &forced = pathinfo.y;

  bool ignore_forced = false;
  if((int)forced.size() > res+1) ignore_forced = true;

  // measure the length of the path
  real total_length = 0;<commit_msg>add slightly more allowance for ignoring vert-forcing<commit_after>#include "Bezier.h"
#include <other/core/vector/Matrix4x4.h>
#include <other/core/vector/Matrix.h>
#include <other/core/utility/stl.h>
#include <other/core/python/Class.h>
#include <other/core/python/stl.h>
#include <other/core/geometry/polygon.h>
#include <iostream>
namespace other {

using std::cout;
using std::endl;

template<> OTHER_DEFINE_TYPE(Bezier<2>)
template<> OTHER_DEFINE_TYPE(Knot<2>)

static double interpolate(double v0, double v1, double v2, double v3, double t) {
  Vector<real,4> i(v0,v1,v2,v3);
  Matrix<real,4> mx( -1, 3, -3, 1,
                     3, -6, 3, 0,
                     -3,3, 0, 0,
                     1, 0,0, 0);

  Vector<real,4> a = mx*i; // transpose because of legacy constructor
  return a.w + t*(a.z + t*(a.y + t*a.x));
}

template<int d> static Vector<real,d> point(Vector<real,d> v0, Vector<real,d> v1, Vector<real,d> v2, Vector<real,d> v3, double t) {
  Vector<real,d> result;
  for (int i = 0; i < d; i++)
    result[i] = interpolate(v0[i],v1[i],v2[i],v3[i],t);
  return result;
}

template<int d> Tuple<Array<Vector<real,d>>, vector<int>> Bezier<d>::evaluate_core(const InvertibleBox& range, int res) const{
  Array<Vector<real,d>> path;
  vector<int> forced;

  if (knots.size()<=1) return tuple(path,forced);
  Vector<real,d> p1, p2, p3, p4;

  auto it = knots.upper_bound(range.begin);
  auto end = knots.lower_bound(range.end);
  if (end == knots.end()) end--;
  if (it!=knots.begin()) it--;
  OTHER_ASSERT(it!=knots.end() && end!=knots.end());
  while(it!=end){
    //jump across null segment end->beginning for closed
    if(b_closed && it->first == t_max()){
      if(range.end == t_min() || range.end == t_max())
        break;
      it = knots.begin();
    }

    p1 = it->second->pt;
    p2 = it->second->tangent_out;

    it++;
    if(it == knots.end()) it = knots.begin(); // wrap around at end

    p3 = it->second->tangent_in;
    p4 = it->second->pt;

    if ((p4-p2).magnitude() > 1e-8) {
      // first point in this segment
      forced.push_back(path.size());
      path.append(other::point(p1,p2,p3,p4,0));

      for (int j=1;j<res;j++) {
        real t = j/(real)(res); // (0,1)
        path.append(other::point(p1,p2,p3,p4,t));
      }
    }
  }
  // last point
  forced.push_back(path.size());
  path.append(end->second->pt);

  return tuple(path, forced);
}

template<int d> Array<Vector<real,d>> Bezier<d>::evaluate(const InvertibleBox& range, int res) const{
  return evaluate_core(range, res).x;
}

template<int d> real Bezier<d>::arclength(const InvertibleBox& range, int res) const {
  Array<Vector<real,d>> path = evaluate(range,std::max(res, 500));

  // measure the length of the path
  real total_length = 0;
  for (int i = 1; i < (int)path.size(); ++i) {
    total_length += (path[i-1] - path[i]).magnitude();
  }

  return total_length;
}

template<int d> Array<Vector<real,d>> Bezier<d>::alen_evaluate(const InvertibleBox& range, int res) const{
  const bool debug = false;

  if (debug)
    std::cout << "sampling range " << range << " with " << res << " segments." << " bezier range: " << t_range << std::endl;

  auto pathinfo = evaluate_core(range,std::max(10*res, 500));
  Array<Vector<real,d>> const &path = pathinfo.x;
  vector<int> const &forced = pathinfo.y;

  bool ignore_forced = false;
  if((int)forced.size() >= res+1) ignore_forced = true;

  // measure the length of the path
  real total_length = 0;
{'fraction_non_alphanumeric': 0.1847179933304335, 'fraction_numerical': 0.022618529795563287, 'mean_word_length': 3.5561426684280053, 'pattern_counts': {'":': 0, '<': 135, '<?xml version=': 0, '>': 123, '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': '467344', 'n_tokens_mistral': 2733, 'n_tokens_neox': 2619, 'n_words': 593}