diff --git a/Makefile.am b/Makefile.am
index a761b37f..56803449 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -12,6 +12,8 @@ SUBDIRS = test
UTIL_FILES = \
backtrace.hpp \
+ bezier.cpp \
+ bezier.hpp \
bitwise.cpp \
bitwise.hpp \
colour.cpp \
diff --git a/bezier.cpp b/bezier.cpp
new file mode 100644
index 00000000..407dfc91
--- /dev/null
+++ b/bezier.cpp
@@ -0,0 +1,124 @@
+/*
+ * This file is part of libgim.
+ *
+ * libgim is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * libgim is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libgim. If not, see .
+ *
+ * Copyright 2015 Danny Robson
+ */
+
+#include "bezier.hpp"
+
+#include "debug.hpp"
+
+#include
+#include
+
+
+//-----------------------------------------------------------------------------
+template
+util::bezier::bezier (const util::point2f _points[S])
+{
+ std::copy (_points, _points + S, m_points);
+}
+
+
+//-----------------------------------------------------------------------------
+namespace util {
+ template <>
+ point2f
+ bezier<2>::eval (float t)
+ {
+ CHECK_GE (t, 0);
+ CHECK_LE (t, 1);
+
+ auto v0 = t * m_points[0];
+ auto v1 = (1 - t) * m_points[1];
+
+ return {
+ v0.x + v1.x,
+ v0.y + v0.y
+ };
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+namespace util {
+ template <>
+ point2f
+ bezier<3>::eval (float t)
+ {
+ CHECK_GE (t, 0);
+ CHECK_LE (t, 1);
+
+ auto v0 = pow2 (1 - t) * m_points[0];
+ auto v1 = 2 * (1 - t) * t * m_points[1];
+ auto v2 = pow2 (t) * m_points[2];
+
+ return {
+ v0.x + v1.x + v2.x,
+ v0.y + v1.y + v2.y
+ };
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+namespace util {
+ template <>
+ point2f
+ bezier<4>::eval (float t)
+ {
+ CHECK_GE (t, 0);
+ CHECK_LE (t, 1);
+
+ auto v0 = pow (1 - t, 3) * m_points[0];
+ auto v1 = 3 * pow2 (1 - t) * t * m_points[1];
+ auto v2 = 3 * pow2 (1 - t) * t * m_points[2];
+ auto v3 = pow (t, 3) * m_points[3];
+
+ return {
+ v0.x + v1.x + v2.x + v3.x,
+ v0.y + v1.y + v2.y + v3.y
+ };
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+template
+util::point2f&
+util::bezier::operator[] (size_t idx)
+{
+ CHECK_LT (idx, S);
+
+ return m_points[idx];
+}
+
+
+//-----------------------------------------------------------------------------
+template
+const util::point2f&
+util::bezier::operator[] (size_t idx) const
+{
+ CHECK_LT (idx, S);
+
+ return m_points[idx];
+}
+
+
+//-----------------------------------------------------------------------------
+template class util::bezier<2>;
+template class util::bezier<3>;
+template class util::bezier<4>;
diff --git a/bezier.hpp b/bezier.hpp
new file mode 100644
index 00000000..75bdef7d
--- /dev/null
+++ b/bezier.hpp
@@ -0,0 +1,41 @@
+/*
+ * This file is part of libgim.
+ *
+ * libgim is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version.
+ *
+ * libgim is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with libgim. If not, see .
+ *
+ * Copyright 2015 Danny Robson
+ */
+
+#ifndef __UTIL_BEZIER_HPP
+#define __UTIL_BEZIER_HPP
+
+#include "point.hpp"
+
+namespace util {
+ template
+ class bezier {
+ bezier (const util::point2f[S]);
+
+ point2f eval (float t);
+ float distance (point2f);
+
+ point2f& operator[] (size_t idx);
+ const point2f& operator[] (size_t idx) const;
+
+ private:
+ point2f m_points[S];
+ };
+}
+
+#endif