#include <cstdio>
#include <cmath>
// vec2 definition:
//==============================================================================
template<typename T>
class vec2
{
public:
vec2()=default;
vec2(const T &x,const T &y):r{x,y} {};
explicit vec2(const T *src):r{src[0],src[1]} {};
vec2(const vec2 &src)=default;
vec2<T> &operator=(const vec2 &src)=default;
vec2<T> &operator+=(const vec2 &src)
{
for(int i=0;i<2;++i) r[i]+=src.r[i];
return *this;
};
vec2<T> &operator-=(const vec2 &src)
{
for(int i=0;i<2;++i) r[i]-=src.r[i];
return *this;
};
vec2<T> &operator*=(const T &s)
{
for(int i=0;i<2;++i) r[i]*=s;
return *this;
};
vec2<T> &operator/=(const T &s)
{
for(int i=0;i<2;++i) r[i]/=s;
return *this;
};
const vec2<T> operator+() const {return {+r[0],+r[1]};};
const vec2<T> operator-() const {return {-r[0],-r[1]};};
friend const vec2<T> operator+(const vec2<T> &l,const vec2<T> &r)
{
return {l.r[0]+r.r[0],l.r[1]+r.r[1]};
};
friend const vec2<T> operator-(const vec2<T> &l,const vec2<T> &r)
{
return {l.r[0]-r.r[0],l.r[1]-r.r[1]};
};
friend const vec2<T> operator*(const vec2<T> &l,const T &r)
{
return {l.r[0]*r,l.r[1]*r};
};
friend const vec2<T> operator*(const T &l,const vec2<T> &r)
{
return {l*r.r[0],l*r.r[1]};
};
friend const vec2<T> operator/(const vec2<T> &l,const T &r)
{
return {l.r[0]/r,l.r[1]/r};
};
friend const T operator*(const vec2<T> &l,const vec2<T> &r)
{
return l.r[0]*r.r[0]+l.r[1]*r.r[1];
};
friend const T operator%(const vec2<T> &l,const vec2<T> &r)
{
return l.r[0]*r.r[1]-l.r[1]*r.r[0];
};
friend bool operator==(const vec2<T> &l,const vec2<T> &r)
{
return (l.r[0]==r.r[0]&&l.r[1]==r.r[1]);
};
friend bool operator!=(const vec2<T> &l,const vec2<T> &r)
{
return (l.r[0]!=r.r[0]||l.r[1]!=r.r[1]);
};
static const vec2<T> mul(const vec2<T> &l,const vec2<T> &r)
{
return {l[0]*r[0],l[1]*r[1]};
};
T &operator[](int i) {return r[i];};
const T &operator[](int i) const {return r[i];};
template<typename S>
const vec2<S> convert() const {return vec2<S>{S(r[0]),S(r[1])};};
T *data() {return r;};
const T *data() const {return r;};
private:
T r[2];
};
//==============================================================================
// End of vec2 definition.
typedef vec2<float> vec2f;
vec2f catmull_rom(
const vec2f &p0,
const vec2f &p1,
const vec2f &m0,
const vec2f &m1,
float t
)
{
return
(2.0f*t*t*t-3.0f*t*t+1.0f)*p0+
(t*t*t-2.0f*t*t+t)*m0+
(-2.0f*t*t*t+3.0f*t*t)*p1+
(t*t*t-t*t)*m1;
}
vec2f catmull_rom_deriv(
const vec2f &p0,
const vec2f &p1,
const vec2f &m0,
const vec2f &m1,
float t)
{
return
(6.0f*t*t-6.0f*t)*p0+
(3.0f*t*t-4.0f*t+1.0f)*m0+
(-6.0f*t*t+6.0f*t)*p1+
(3.0f*t*t-2.0f*t)*m1;
}
float catmull_rom_length(
const vec2f &p0,
const vec2f &p1,
const vec2f &m0,
const vec2f &m1,
float t0,
float t1,
float eps)
{
if(t1<t0)
return -catmull_rom_length(p0,p1,m0,m1,t1,t0,eps);
if(t1-t0>eps)
{
float tm=0.5f*(t0+t1);
return
catmull_rom_length(p0,p1,m0,m1,t0,tm,eps)+
catmull_rom_length(p0,p1,m0,m1,tm,t1,eps);
}
else
{
vec2f d=
catmull_rom(p0,p1,m0,m1,t1)-
catmull_rom(p0,p1,m0,m1,t0);
return std::sqrt(d*d);
}
}
//==============================================================================
float catmull_rom_dt_1(
const vec2f &p0,
const vec2f &p1,
const vec2f &m0,
const vec2f &m1,
float t,
float ds)
{
vec2f v=catmull_rom_deriv(p0,p1,m0,m1,t);
return ds/std::sqrt(v*v);
}
float catmull_rom_dt_2(
const vec2f &p0,
const vec2f &p1,
const vec2f &m0,
const vec2f &m1,
float t,
float ds)
{
vec2f v0=catmull_rom_deriv(p0,p1,m0,m1,t);
float dt0=
ds/std::sqrt(v0*v0);
vec2f v1=catmull_rom_deriv(p0,p1,m0,m1,t+dt0);
float
a=0.5f*(std::sqrt(v1*v1)-std::sqrt(v0*v0))/dt0,
b=std::sqrt(v0*v0),
c=-ds;
return -c/b-a*c*c/(b*b*b);
}
//==============================================================================
void print_vec(const vec2f &v)
{
printf("{%f,%f}\n",v[0],v[1]);
}
//==============================================================================
int main()
{
vec2f
p0={0.0f,0.0f},
p1={1.0f,0.0f},
m0={1.0f,1.0f},
m1={0.0f,-1.0f};
printf("Length measurement test:\n");
for(int i=0;i<2;++i)
{
const float eps=
i==0?
1.0f/256.0f:
1.0f/4096.0f;
printf(" eps=%f:\n",eps);
for(float t=0.0f;t<=1.0f;t+=0.125f)
printf(" t=%f: length=%f\n",
t,
catmull_rom_length(
p0,p1,m0,m1,
0.0f,t,
eps));
}
printf("\n");
printf("Stepping test:\n");
for(int i=0;i<2;++i)
{
const float ds=
i==0?
1.0f/64.0f:
1.0f/5.0f;
printf(" step=%f\n",ds);
printf("Version 1:\n");
for(float t=0.0f,s=0.0f;t<1.0f;)
{
printf(" s=%f: delta=%+f\n",
s,
catmull_rom_length(
p0,p1,m0,m1,
0.0f,t,
1.0f/4096.0f)-s);
t+=catmull_rom_dt_1(p0,p1,m0,m1,t,ds);
s+=ds;
}
printf("Version 2:\n");
for(float t=0.0f,s=0.0f;t<1.0f;)
{
printf(" s=%f: delta=%+f\n",
s,
catmull_rom_length(
p0,p1,m0,m1,
0.0f,t,
1.0f/4096.0f)-s);
t+=catmull_rom_dt_2(p0,p1,m0,m1,t,ds);
s+=ds;
}
printf("\n");
}
return 0;
}
I2luY2x1ZGUgPGNzdGRpbz4KI2luY2x1ZGUgPGNtYXRoPgoKLy8gdmVjMiBkZWZpbml0aW9uOgovLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKdGVtcGxhdGU8dHlwZW5hbWUgVD4KY2xhc3MgdmVjMgp7CnB1YmxpYzoKICAgIHZlYzIoKT1kZWZhdWx0OwogICAgdmVjMihjb25zdCBUICZ4LGNvbnN0IFQgJnkpOnJ7eCx5fSB7fTsKICAgIGV4cGxpY2l0IHZlYzIoY29uc3QgVCAqc3JjKTpye3NyY1swXSxzcmNbMV19IHt9OwogICAgdmVjMihjb25zdCB2ZWMyICZzcmMpPWRlZmF1bHQ7CgogICAgdmVjMjxUPiAmb3BlcmF0b3I9KGNvbnN0IHZlYzIgJnNyYyk9ZGVmYXVsdDsKCiAgICB2ZWMyPFQ+ICZvcGVyYXRvcis9KGNvbnN0IHZlYzIgJnNyYykKICAgIHsKICAgICAgICBmb3IoaW50IGk9MDtpPDI7KytpKSByW2ldKz1zcmMucltpXTsKICAgICAgICByZXR1cm4gKnRoaXM7CiAgICB9OwogICAgdmVjMjxUPiAmb3BlcmF0b3ItPShjb25zdCB2ZWMyICZzcmMpCiAgICB7CiAgICAgICAgZm9yKGludCBpPTA7aTwyOysraSkgcltpXS09c3JjLnJbaV07CiAgICAgICAgcmV0dXJuICp0aGlzOwogICAgfTsKICAgIHZlYzI8VD4gJm9wZXJhdG9yKj0oY29uc3QgVCAmcykKICAgIHsKICAgICAgICBmb3IoaW50IGk9MDtpPDI7KytpKSByW2ldKj1zOwogICAgICAgIHJldHVybiAqdGhpczsKICAgIH07CiAgICB2ZWMyPFQ+ICZvcGVyYXRvci89KGNvbnN0IFQgJnMpCiAgICB7CiAgICAgICAgZm9yKGludCBpPTA7aTwyOysraSkgcltpXS89czsKICAgICAgICByZXR1cm4gKnRoaXM7CiAgICB9OwoKICAgIGNvbnN0IHZlYzI8VD4gb3BlcmF0b3IrKCkgY29uc3Qge3JldHVybiB7K3JbMF0sK3JbMV19O307CiAgICBjb25zdCB2ZWMyPFQ+IG9wZXJhdG9yLSgpIGNvbnN0IHtyZXR1cm4gey1yWzBdLC1yWzFdfTt9OwoKICAgIGZyaWVuZCBjb25zdCB2ZWMyPFQ+IG9wZXJhdG9yKyhjb25zdCB2ZWMyPFQ+ICZsLGNvbnN0IHZlYzI8VD4gJnIpCiAgICB7CiAgICAgICAgcmV0dXJuIHtsLnJbMF0rci5yWzBdLGwuclsxXStyLnJbMV19OwogICAgfTsKICAgIGZyaWVuZCBjb25zdCB2ZWMyPFQ+IG9wZXJhdG9yLShjb25zdCB2ZWMyPFQ+ICZsLGNvbnN0IHZlYzI8VD4gJnIpCiAgICB7CiAgICAgICAgcmV0dXJuIHtsLnJbMF0tci5yWzBdLGwuclsxXS1yLnJbMV19OwogICAgfTsKCiAgICBmcmllbmQgY29uc3QgdmVjMjxUPiBvcGVyYXRvciooY29uc3QgdmVjMjxUPiAmbCxjb25zdCBUICZyKQogICAgewogICAgICAgIHJldHVybiB7bC5yWzBdKnIsbC5yWzFdKnJ9OwogICAgfTsKICAgIGZyaWVuZCBjb25zdCB2ZWMyPFQ+IG9wZXJhdG9yKihjb25zdCBUICZsLGNvbnN0IHZlYzI8VD4gJnIpCiAgICB7CiAgICAgICAgcmV0dXJuIHtsKnIuclswXSxsKnIuclsxXX07CiAgICB9OwogICAgZnJpZW5kIGNvbnN0IHZlYzI8VD4gb3BlcmF0b3IvKGNvbnN0IHZlYzI8VD4gJmwsY29uc3QgVCAmcikKICAgIHsKICAgICAgICByZXR1cm4ge2wuclswXS9yLGwuclsxXS9yfTsKICAgIH07CgogICAgZnJpZW5kIGNvbnN0IFQgb3BlcmF0b3IqKGNvbnN0IHZlYzI8VD4gJmwsY29uc3QgdmVjMjxUPiAmcikKICAgIHsKICAgICAgICByZXR1cm4gbC5yWzBdKnIuclswXStsLnJbMV0qci5yWzFdOwogICAgfTsKICAgIGZyaWVuZCBjb25zdCBUIG9wZXJhdG9yJShjb25zdCB2ZWMyPFQ+ICZsLGNvbnN0IHZlYzI8VD4gJnIpCiAgICB7CiAgICAgICAgcmV0dXJuIGwuclswXSpyLnJbMV0tbC5yWzFdKnIuclswXTsKICAgIH07CgogICAgZnJpZW5kIGJvb2wgb3BlcmF0b3I9PShjb25zdCB2ZWMyPFQ+ICZsLGNvbnN0IHZlYzI8VD4gJnIpCiAgICB7CiAgICAgICAgcmV0dXJuIChsLnJbMF09PXIuclswXSYmbC5yWzFdPT1yLnJbMV0pOwogICAgfTsKICAgIGZyaWVuZCBib29sIG9wZXJhdG9yIT0oY29uc3QgdmVjMjxUPiAmbCxjb25zdCB2ZWMyPFQ+ICZyKQogICAgewogICAgICAgIHJldHVybiAobC5yWzBdIT1yLnJbMF18fGwuclsxXSE9ci5yWzFdKTsKICAgIH07CgogICAgc3RhdGljIGNvbnN0IHZlYzI8VD4gbXVsKGNvbnN0IHZlYzI8VD4gJmwsY29uc3QgdmVjMjxUPiAmcikKICAgIHsKICAgICAgICByZXR1cm4ge2xbMF0qclswXSxsWzFdKnJbMV19OwogICAgfTsKCiAgICBUICZvcGVyYXRvcltdKGludCBpKSB7cmV0dXJuIHJbaV07fTsKICAgIGNvbnN0IFQgJm9wZXJhdG9yW10oaW50IGkpIGNvbnN0IHtyZXR1cm4gcltpXTt9OwoKICAgIHRlbXBsYXRlPHR5cGVuYW1lIFM+CiAgICBjb25zdCB2ZWMyPFM+IGNvbnZlcnQoKSBjb25zdCB7cmV0dXJuIHZlYzI8Uz57UyhyWzBdKSxTKHJbMV0pfTt9OwoKICAgIFQgKmRhdGEoKSB7cmV0dXJuIHI7fTsKICAgIGNvbnN0IFQgKmRhdGEoKSBjb25zdCB7cmV0dXJuIHI7fTsKcHJpdmF0ZToKICAgIFQgclsyXTsKfTsKCi8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ci8vIEVuZCBvZiB2ZWMyIGRlZmluaXRpb24uCgp0eXBlZGVmIHZlYzI8ZmxvYXQ+IHZlYzJmOwoKdmVjMmYgY2F0bXVsbF9yb20oCgljb25zdCB2ZWMyZiAmcDAsCgljb25zdCB2ZWMyZiAmcDEsCgljb25zdCB2ZWMyZiAmbTAsCgljb25zdCB2ZWMyZiAmbTEsCglmbG9hdCB0CgkpCnsKCXJldHVybgoJCSgyLjBmKnQqdCp0LTMuMGYqdCp0KzEuMGYpKnAwKwoJCSh0KnQqdC0yLjBmKnQqdCt0KSptMCsKCQkoLTIuMGYqdCp0KnQrMy4wZip0KnQpKnAxKwoJCSh0KnQqdC10KnQpKm0xOwp9Cgp2ZWMyZiBjYXRtdWxsX3JvbV9kZXJpdigKCWNvbnN0IHZlYzJmICZwMCwKCWNvbnN0IHZlYzJmICZwMSwKCWNvbnN0IHZlYzJmICZtMCwKCWNvbnN0IHZlYzJmICZtMSwKCWZsb2F0IHQpCnsKCXJldHVybgoJCSg2LjBmKnQqdC02LjBmKnQpKnAwKwoJCSgzLjBmKnQqdC00LjBmKnQrMS4wZikqbTArCgkJKC02LjBmKnQqdCs2LjBmKnQpKnAxKwoJCSgzLjBmKnQqdC0yLjBmKnQpKm0xOwp9CgpmbG9hdCBjYXRtdWxsX3JvbV9sZW5ndGgoCgljb25zdCB2ZWMyZiAmcDAsCgljb25zdCB2ZWMyZiAmcDEsCgljb25zdCB2ZWMyZiAmbTAsCgljb25zdCB2ZWMyZiAmbTEsCglmbG9hdCB0MCwKCWZsb2F0IHQxLAoJZmxvYXQgZXBzKQp7CglpZih0MTx0MCkKCQlyZXR1cm4gLWNhdG11bGxfcm9tX2xlbmd0aChwMCxwMSxtMCxtMSx0MSx0MCxlcHMpOwoJaWYodDEtdDA+ZXBzKQoJewoJCWZsb2F0IHRtPTAuNWYqKHQwK3QxKTsKCQlyZXR1cm4KCQkJY2F0bXVsbF9yb21fbGVuZ3RoKHAwLHAxLG0wLG0xLHQwLHRtLGVwcykrCgkJCWNhdG11bGxfcm9tX2xlbmd0aChwMCxwMSxtMCxtMSx0bSx0MSxlcHMpOwoJfQoJZWxzZQoJewoJCXZlYzJmIGQ9CgkJCWNhdG11bGxfcm9tKHAwLHAxLG0wLG0xLHQxKS0KCQkJY2F0bXVsbF9yb20ocDAscDEsbTAsbTEsdDApOwoJCXJldHVybiBzdGQ6OnNxcnQoZCpkKTsKCX0KfQoKLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCmZsb2F0IGNhdG11bGxfcm9tX2R0XzEoCgljb25zdCB2ZWMyZiAmcDAsCgljb25zdCB2ZWMyZiAmcDEsCgljb25zdCB2ZWMyZiAmbTAsCgljb25zdCB2ZWMyZiAmbTEsCglmbG9hdCB0LAoJZmxvYXQgZHMpCnsKCXZlYzJmIHY9Y2F0bXVsbF9yb21fZGVyaXYocDAscDEsbTAsbTEsdCk7CglyZXR1cm4gZHMvc3RkOjpzcXJ0KHYqdik7Cn0KCmZsb2F0IGNhdG11bGxfcm9tX2R0XzIoCgljb25zdCB2ZWMyZiAmcDAsCgljb25zdCB2ZWMyZiAmcDEsCgljb25zdCB2ZWMyZiAmbTAsCgljb25zdCB2ZWMyZiAmbTEsCglmbG9hdCB0LAoJZmxvYXQgZHMpCnsKCXZlYzJmIHYwPWNhdG11bGxfcm9tX2Rlcml2KHAwLHAxLG0wLG0xLHQpOwoJZmxvYXQgZHQwPQoJCWRzL3N0ZDo6c3FydCh2MCp2MCk7Cgl2ZWMyZiB2MT1jYXRtdWxsX3JvbV9kZXJpdihwMCxwMSxtMCxtMSx0K2R0MCk7CglmbG9hdAoJCWE9MC41Ziooc3RkOjpzcXJ0KHYxKnYxKS1zdGQ6OnNxcnQodjAqdjApKS9kdDAsCgkJYj1zdGQ6OnNxcnQodjAqdjApLAoJCWM9LWRzOwoJcmV0dXJuIC1jL2ItYSpjKmMvKGIqYipiKTsKfQoKLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCnZvaWQgcHJpbnRfdmVjKGNvbnN0IHZlYzJmICZ2KQp7CglwcmludGYoInslZiwlZn1cbiIsdlswXSx2WzFdKTsKfQoKLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCmludCBtYWluKCkKewoJdmVjMmYKCQlwMD17MC4wZiwwLjBmfSwKCQlwMT17MS4wZiwwLjBmfSwKCQltMD17MS4wZiwxLjBmfSwKCQltMT17MC4wZiwtMS4wZn07CgoJcHJpbnRmKCJMZW5ndGggbWVhc3VyZW1lbnQgdGVzdDpcbiIpOwoJZm9yKGludCBpPTA7aTwyOysraSkKCXsKCQljb25zdCBmbG9hdCBlcHM9CgkJCWk9PTA/CgkJCTEuMGYvMjU2LjBmOgoJCQkxLjBmLzQwOTYuMGY7CgkJcHJpbnRmKCIgIGVwcz0lZjpcbiIsZXBzKTsKCQlmb3IoZmxvYXQgdD0wLjBmO3Q8PTEuMGY7dCs9MC4xMjVmKQoJCQlwcmludGYoIiAgICB0PSVmOiBsZW5ndGg9JWZcbiIsCgkJCQl0LAoJCQkJY2F0bXVsbF9yb21fbGVuZ3RoKAoJCQkJCXAwLHAxLG0wLG0xLAoJCQkJCTAuMGYsdCwKCQkJCQllcHMpKTsKCX0KCXByaW50ZigiXG4iKTsKCXByaW50ZigiU3RlcHBpbmcgdGVzdDpcbiIpOwoJZm9yKGludCBpPTA7aTwyOysraSkKCXsKCQljb25zdCBmbG9hdCBkcz0KCQkJaT09MD8KCQkJMS4wZi82NC4wZjoKCQkJMS4wZi81LjBmOwoJCXByaW50ZigiICBzdGVwPSVmXG4iLGRzKTsKCQlwcmludGYoIlZlcnNpb24gMTpcbiIpOwoJCWZvcihmbG9hdCB0PTAuMGYscz0wLjBmO3Q8MS4wZjspCgkJewoJCQlwcmludGYoIiAgcz0lZjogZGVsdGE9JStmXG4iLAoJCQkJcywKCQkJCWNhdG11bGxfcm9tX2xlbmd0aCgKCQkJCQlwMCxwMSxtMCxtMSwKCQkJCQkwLjBmLHQsCgkJCQkJMS4wZi80MDk2LjBmKS1zKTsKCQkJdCs9Y2F0bXVsbF9yb21fZHRfMShwMCxwMSxtMCxtMSx0LGRzKTsKCQkJcys9ZHM7CgkJfQoJCXByaW50ZigiVmVyc2lvbiAyOlxuIik7CgkJZm9yKGZsb2F0IHQ9MC4wZixzPTAuMGY7dDwxLjBmOykKCQl7CgkJCXByaW50ZigiICBzPSVmOiBkZWx0YT0lK2ZcbiIsCgkJCQlzLAoJCQkJY2F0bXVsbF9yb21fbGVuZ3RoKAoJCQkJCXAwLHAxLG0wLG0xLAoJCQkJCTAuMGYsdCwKCQkJCQkxLjBmLzQwOTYuMGYpLXMpOwoJCQl0Kz1jYXRtdWxsX3JvbV9kdF8yKHAwLHAxLG0wLG0xLHQsZHMpOwoJCQlzKz1kczsKCQl9CgkJcHJpbnRmKCJcbiIpOwoJfQoJcmV0dXJuIDA7Cn0=