125 lines
3.1 KiB
C++
125 lines
3.1 KiB
C++
/*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* Copyright 2015-2016 Danny Robson <danny@nerdcruft.net>
|
|
*/
|
|
|
|
#include "bezier.hpp"
|
|
|
|
#include <array>
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
namespace cruft {
|
|
template <>
|
|
point2f
|
|
bezier<1>::eval (float t) const
|
|
{
|
|
CHECK_GE (t, 0.f);
|
|
CHECK_LE (t, 1.f);
|
|
|
|
auto v0 = (1 - t) * m_points[0];
|
|
auto v1 = t * m_points[1];
|
|
|
|
return {
|
|
v0.x + v1.x,
|
|
v0.y + v1.y
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
constexpr
|
|
cruft::vector2f
|
|
orthonormal (cruft::vector2f v)
|
|
{
|
|
const auto len = norm (v);
|
|
CHECK_NEZ (len);
|
|
return cruft::vector2f { -v.y / len, v.x / len };
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
namespace cruft {
|
|
template <>
|
|
float
|
|
bezier<1>::closest (cruft::point2f q) const noexcept
|
|
{
|
|
const auto ab = m_points[1] - m_points[0];
|
|
const auto aq = q - m_points[0];
|
|
|
|
return dot (aq, ab) / dot (ab, ab);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
namespace cruft {
|
|
template <>
|
|
float
|
|
bezier<1>::distance (cruft::point2f q) const noexcept
|
|
{
|
|
const auto ab = m_points[1] - m_points[0];
|
|
const auto t = clamp (closest (q), 0.f, 1.f);
|
|
const auto p = m_points[0] + t * ab;
|
|
|
|
return cruft::distance (q, p);
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
namespace cruft {
|
|
template <>
|
|
sdot_t
|
|
bezier<1>::sdot (const point2f q) const noexcept
|
|
{
|
|
// find the closest parameter 't' to the point 'q' for the parametric line
|
|
const auto qa = m_points[0] - q;
|
|
const auto ab = m_points[1] - m_points[0];
|
|
const auto t = closest (q);
|
|
|
|
// find the vector to, and distance to, the nearest endpoint 'e'
|
|
const auto qe = m_points[t > 0.5] - q;
|
|
const auto d_e = norm (qe);
|
|
|
|
// if we're on the segment return the distance to the segment
|
|
if (t >= 0 && t <= 1) {
|
|
const auto ortho = cruft::vector2f { -ab.y, ab.x } / norm (ab);
|
|
const auto d = dot (ortho, qa);
|
|
|
|
// not _entirely_ sure why we need this condition
|
|
if (abs (d) <= d_e) {
|
|
return { d, 0 };
|
|
}
|
|
}
|
|
|
|
// return the distance and angle to the endpoint
|
|
return {
|
|
sign (cross (ab, qa)) * d_e,
|
|
abs (
|
|
dot (normalised (ab), normalised (qe))
|
|
)
|
|
};
|
|
}
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
namespace cruft {
|
|
template <>
|
|
std::array<cruft::vector2f,2>
|
|
bezier<1>::coeffs (void) const
|
|
{
|
|
auto &v = m_coeffs;
|
|
|
|
return {
|
|
-1.f * v[1] + 1.f * v[0],
|
|
+1.f * v[1],
|
|
};
|
|
}
|
|
}
|