From 32bd5feb81a88f15a6f3047d1c7634bc5d28a11c Mon Sep 17 00:00:00 2001
From: JasonChmn <jason.chemin@hotmail.fr>
Date: Mon, 8 Jul 2019 16:30:55 +0200
Subject: [PATCH] [piecewise_curve] Create conversions for piecewise_curve, add
 tests OK

---
 CMakeLists.txt                          |   1 +
 include/curves/CMakeLists.txt           |   1 +
 include/curves/bezier_curve.h           |   5 +
 include/curves/cubic_hermite_spline.h   |  58 +-
 include/curves/piecewise_curve.h        |  55 +-
 include/curves/polynomial.h             |   3 +-
 include/curves/proto/CMakeLists.txt     |   5 +
 include/curves/proto/Curves_proto.pb.cc | 886 ++++++++++++++++++++++++
 include/curves/proto/Curves_proto.pb.h  | 490 +++++++++++++
 include/curves/proto/Curves_proto.proto |  22 +
 tests/Main.cpp                          |  14 +-
 11 files changed, 1506 insertions(+), 34 deletions(-)
 create mode 100644 include/curves/proto/CMakeLists.txt
 create mode 100644 include/curves/proto/Curves_proto.pb.cc
 create mode 100644 include/curves/proto/Curves_proto.pb.h
 create mode 100644 include/curves/proto/Curves_proto.proto

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9ef850b..ad783ea 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,6 +18,7 @@ SET(CXX_DISABLE_WERROR True)
 SETUP_HPP_PROJECT()
 
 ADD_REQUIRED_DEPENDENCY(eigen3)
+ADD_REQUIRED_DEPENDENCY(protobuf)
 
 SET(BOOST_COMPONENTS unit_test_framework)
 
diff --git a/include/curves/CMakeLists.txt b/include/curves/CMakeLists.txt
index 8c7c38b..c8c883c 100644
--- a/include/curves/CMakeLists.txt
+++ b/include/curves/CMakeLists.txt
@@ -20,3 +20,4 @@ INSTALL(FILES
   )
 
 ADD_SUBDIRECTORY(helpers)
+ADD_SUBDIRECTORY(proto)
diff --git a/include/curves/bezier_curve.h b/include/curves/bezier_curve.h
index 7ff1405..8a870bc 100644
--- a/include/curves/bezier_curve.h
+++ b/include/curves/bezier_curve.h
@@ -99,6 +99,11 @@ struct bezier_curve : public curve_abc<Time, Numeric, Safe, Point>
         }
     }
 
+    bezier_curve(const bezier_curve& other)
+        : t_min_(other.t_min_), t_max_(other.t_max_), mult_T_(other.mult_T_), size_(other.size_),
+          order_(other.order_), bernstein_(other.bernstein_), control_points_(other.control_points_)
+          {}
+
     ///\brief Destructor
     ~bezier_curve()
     {
diff --git a/include/curves/cubic_hermite_spline.h b/include/curves/cubic_hermite_spline.h
index eddd5b5..08c6736 100644
--- a/include/curves/cubic_hermite_spline.h
+++ b/include/curves/cubic_hermite_spline.h
@@ -38,29 +38,6 @@ struct cubic_hermite_spline : public curve_abc<Time, Numeric, Safe, Point>
     typedef std::vector< pair_point_tangent_t ,Eigen::aligned_allocator<Point> > t_pair_point_tangent_t;
     typedef std::vector<Time> vector_time_t;
     typedef Numeric num_t;
-
-    /*Attributes*/
-    public:
-    /// Vector of pair < Point, Tangent >.
-    t_pair_point_tangent_t control_points_;
-    /// Vector of Time corresponding to time of each N control points : time at \f$P_0, P_1, P_2, ..., P_N\f$.
-    /// Exemple : \f$( 0., 0.5, 0.9, ..., 4.5 )\f$ with values corresponding to times for \f$P_0, P_1, P_2, ..., P_N\f$ respectively.
-    vector_time_t time_control_points_;
-
-    /// Vector of Time corresponding to time duration of each subspline.<br>
-    /// For N control points with time \f$T_{P_0}, T_{P_1}, T_{P_2}, ..., T_{P_N}\f$ respectively,
-    /// duration of each subspline is : ( T_{P_1}-T_{P_0}, T_{P_2}-T_{P_1}, ..., T_{P_N}-T_{P_{N-1} )<br>
-    /// It contains \f$N-1\f$ durations. 
-    vector_time_t duration_splines_;
-    /// Starting time of cubic hermite spline : T_min_ is equal to first time of control points.
-    /*const*/ Time T_min_;
-    /// Ending time of cubic hermite spline : T_max_ is equal to last time of control points.
-    /*const*/ Time T_max_;
-    /// Number of control points (pairs).
-    std::size_t size_;
-    /// Degree (Cubic so degree 3)
-    static const std::size_t degree_ = 3;
-    /*Attributes*/
     
     public:
     /// \brief Constructor.
@@ -70,6 +47,7 @@ struct cubic_hermite_spline : public curve_abc<Time, Numeric, Safe, Point>
     ///
     template<typename In>
     cubic_hermite_spline(In PairsBegin, In PairsEnd, const vector_time_t & time_control_points)
+    : order_(3)
     {
         // Check size of pairs container.
         std::size_t const size(std::distance(PairsBegin, PairsEnd));
@@ -87,6 +65,12 @@ struct cubic_hermite_spline : public curve_abc<Time, Numeric, Safe, Point>
         setTime(time_control_points);
     }
 
+    cubic_hermite_spline(const cubic_hermite_spline& other)
+        : t_min_(other.t_min_), t_max_(other.t_max_), size_(other.size_), order_(other.order_), 
+          control_points_(other.control_points_), time_control_points_(other.time_control_points_),
+          duration_splines_(other.duration_splines_)
+          {}
+
     /// \brief Destructor.
     virtual ~cubic_hermite_spline(){}
 
@@ -98,7 +82,7 @@ struct cubic_hermite_spline : public curve_abc<Time, Numeric, Safe, Point>
     ///
     virtual Point operator()(const Time t) const
     {
-        if(Safe &! (T_min_ <= t && t <= T_max_))
+        if(Safe &! (t_min_ <= t && t <= t_max_))
         {
             throw std::invalid_argument("can't evaluate cubic hermite spline, out of range");
         }
@@ -130,8 +114,8 @@ struct cubic_hermite_spline : public curve_abc<Time, Numeric, Safe, Point>
     void setTime(const vector_time_t & time_control_points)
     {
         time_control_points_ = time_control_points;
-        T_min_ = time_control_points_.front();
-        T_max_ = time_control_points_.back();
+        t_min_ = time_control_points_.front();
+        t_max_ = time_control_points_.back();
         if (time_control_points.size() != size())
         {
             throw std::length_error("size of time control points should be equal to number of control points");
@@ -365,6 +349,28 @@ struct cubic_hermite_spline : public curve_abc<Time, Numeric, Safe, Point>
     Time virtual max() const{return time_control_points_.back();}
     /*Helpers*/
 
+    /*Attributes*/
+    /// Vector of pair < Point, Tangent >.
+    t_pair_point_tangent_t control_points_;
+    /// Vector of Time corresponding to time of each N control points : time at \f$P_0, P_1, P_2, ..., P_N\f$.
+    /// Exemple : \f$( 0., 0.5, 0.9, ..., 4.5 )\f$ with values corresponding to times for \f$P_0, P_1, P_2, ..., P_N\f$ respectively.
+    vector_time_t time_control_points_;
+
+    /// Vector of Time corresponding to time duration of each subspline.<br>
+    /// For N control points with time \f$T_{P_0}, T_{P_1}, T_{P_2}, ..., T_{P_N}\f$ respectively,
+    /// duration of each subspline is : ( T_{P_1}-T_{P_0}, T_{P_2}-T_{P_1}, ..., T_{P_N}-T_{P_{N-1} )<br>
+    /// It contains \f$N-1\f$ durations. 
+    vector_time_t duration_splines_;
+    /// Starting time of cubic hermite spline : t_min_ is equal to first time of control points.
+    /*const*/ Time t_min_;
+    /// Ending time of cubic hermite spline : t_max_ is equal to last time of control points.
+    /*const*/ Time t_max_;
+    /// Number of control points (pairs).
+    std::size_t size_;
+    /// Degree (Cubic so degree 3)
+    std::size_t order_;
+    /*Attributes*/
+
 };
 
 } // namespace curve
diff --git a/include/curves/piecewise_curve.h b/include/curves/piecewise_curve.h
index bccbe55..49e1440 100644
--- a/include/curves/piecewise_curve.h
+++ b/include/curves/piecewise_curve.h
@@ -11,8 +11,6 @@
 #include "curve_abc.h"
 #include "curve_conversion.h"
 
-#include <typeinfo>
-
 namespace curves
 {
 /// \class PiecewiseCurve.
@@ -80,7 +78,8 @@ struct piecewise_curve : public curve_abc<Time, Numeric, Safe, Point>
     }
 
     ///  \brief Add a new curve to piecewise curve, which should be defined in \f$[T_{min},T_{max}]\f$ where \f$T_{min}\f$
-    ///         is equal to \f$T_{max}\f$ of the actual piecewise curve.
+    ///         is equal to \f$T_{max}\f$ of the actual piecewise curve. The curve added should be of type Curve as defined
+    ///         in the template.
     ///  \param cf : curve to add.
     ///
     void add_curve(const curve_t& cf)
@@ -130,6 +129,56 @@ struct piecewise_curve : public curve_abc<Time, Numeric, Safe, Point>
         return isContinuous;
     }
 
+    template<typename Bezier>
+    piecewise_curve<Time, Numeric, Dim, Safe, Point, T_Point, Bezier> convert_piecewise_curve_to_bezier()
+    {
+        typedef piecewise_curve<Time, Numeric, Dim, Safe, Point, T_Point, Bezier> piecewise_curve_out_t;
+        // Get first curve (segment)
+        curve_t first_curve = curves_.at(0);
+        Bezier first_curve_output = bezier_from_curve<Bezier, curve_t>(first_curve);
+        // Create piecewise curve
+        piecewise_curve_out_t pc_res(first_curve_output);
+        // Convert and add all other curves (segments)
+        for (std::size_t i=1; i<size_; i++)
+        {
+            pc_res.add_curve(bezier_from_curve<Bezier, curve_t>(curves_.at(i)));
+        }
+        return pc_res;
+    }
+
+    template<typename Hermite>
+    piecewise_curve<Time, Numeric, Dim, Safe, Point, T_Point, Hermite> convert_piecewise_curve_to_cubic_hermite()
+    {
+        typedef piecewise_curve<Time, Numeric, Dim, Safe, Point, T_Point, Hermite> piecewise_curve_out_t;
+        // Get first curve (segment)
+        curve_t first_curve = curves_.at(0);
+        Hermite first_curve_output = hermite_from_curve<Hermite, curve_t>(first_curve);
+        // Create piecewise curve
+        piecewise_curve_out_t pc_res(first_curve_output);
+        // Convert and add all other curves (segments)
+        for (std::size_t i=1; i<size_; i++)
+        {
+            pc_res.add_curve(hermite_from_curve<Hermite, curve_t>(curves_.at(i)));
+        }
+        return pc_res;
+    }
+
+    template<typename Polynomial>
+    piecewise_curve<Time, Numeric, Dim, Safe, Point, T_Point, Polynomial> convert_piecewise_curve_to_polynomial()
+    {
+        typedef piecewise_curve<Time, Numeric, Dim, Safe, Point, T_Point, Polynomial> piecewise_curve_out_t;
+        // Get first curve (segment)
+        curve_t first_curve = curves_.at(0);
+        Polynomial first_curve_output = polynomial_from_curve<Polynomial, curve_t>(first_curve);
+        // Create piecewise curve
+        piecewise_curve_out_t pc_res(first_curve_output);
+        // Convert and add all other curves (segments)
+        for (std::size_t i=1; i<size_; i++)
+        {
+            pc_res.add_curve(polynomial_from_curve<Polynomial, curve_t>(curves_.at(i)));
+        }
+        return pc_res;
+    }
 
     private:
 
diff --git a/include/curves/polynomial.h b/include/curves/polynomial.h
index f2b381d..d527ea6 100644
--- a/include/curves/polynomial.h
+++ b/include/curves/polynomial.h
@@ -95,7 +95,8 @@ struct polynomial : public curve_abc<Time, Numeric, Safe, Point>
 
     polynomial(const polynomial& other)
         : coefficients_(other.coefficients_),
-          dim_(other.dim_), order_(other.order_), t_min_(other.t_min_), t_max_(other.t_max_){}
+          dim_(other.dim_), order_(other.order_), t_min_(other.t_min_), t_max_(other.t_max_)
+          {}
 
 
     //polynomial& operator=(const polynomial& other);
diff --git a/include/curves/proto/CMakeLists.txt b/include/curves/proto/CMakeLists.txt
new file mode 100644
index 0000000..a9b8fed
--- /dev/null
+++ b/include/curves/proto/CMakeLists.txt
@@ -0,0 +1,5 @@
+INCLUDE(FindProtobuf)
+FIND_PACKAGE(Protobuf REQUIRED)
+INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR})
+PROTOBUF_GENERATE_CPP(PROTO_SRC PROTO_HEADER Curves_proto.proto)
+ADD_LIBRARY(proto ${PROTO_HEADER} ${PROTO_SRC})
diff --git a/include/curves/proto/Curves_proto.pb.cc b/include/curves/proto/Curves_proto.pb.cc
new file mode 100644
index 0000000..5ef91f7
--- /dev/null
+++ b/include/curves/proto/Curves_proto.pb.cc
@@ -0,0 +1,886 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: Curves_proto.proto
+
+#include "Curves_proto.pb.h"
+
+#include <algorithm>
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/port.h>
+#include <google/protobuf/stubs/once.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format_lite_inl.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/generated_message_reflection.h>
+#include <google/protobuf/reflection_ops.h>
+#include <google/protobuf/wire_format.h>
+// This is a temporary google only hack
+#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+#include "third_party/protobuf/version.h"
+#endif
+// @@protoc_insertion_point(includes)
+namespace Curves_proto {
+class MatrixDefaultTypeInternal {
+ public:
+  ::google::protobuf::internal::ExplicitlyConstructed<Matrix>
+      _instance;
+} _Matrix_default_instance_;
+class Piecewise_polynomial_curveDefaultTypeInternal {
+ public:
+  ::google::protobuf::internal::ExplicitlyConstructed<Piecewise_polynomial_curve>
+      _instance;
+} _Piecewise_polynomial_curve_default_instance_;
+}  // namespace Curves_proto
+namespace protobuf_Curves_5fproto_2eproto {
+void InitDefaultsMatrixImpl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  ::google::protobuf::internal::InitProtobufDefaultsForceUnique();
+#else
+  ::google::protobuf::internal::InitProtobufDefaults();
+#endif  // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  {
+    void* ptr = &::Curves_proto::_Matrix_default_instance_;
+    new (ptr) ::Curves_proto::Matrix();
+    ::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
+  }
+  ::Curves_proto::Matrix::InitAsDefaultInstance();
+}
+
+void InitDefaultsMatrix() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsMatrixImpl);
+}
+
+void InitDefaultsPiecewise_polynomial_curveImpl() {
+  GOOGLE_PROTOBUF_VERIFY_VERSION;
+
+#ifdef GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  ::google::protobuf::internal::InitProtobufDefaultsForceUnique();
+#else
+  ::google::protobuf::internal::InitProtobufDefaults();
+#endif  // GOOGLE_PROTOBUF_ENFORCE_UNIQUENESS
+  protobuf_Curves_5fproto_2eproto::InitDefaultsMatrix();
+  {
+    void* ptr = &::Curves_proto::_Piecewise_polynomial_curve_default_instance_;
+    new (ptr) ::Curves_proto::Piecewise_polynomial_curve();
+    ::google::protobuf::internal::OnShutdownDestroyMessage(ptr);
+  }
+  ::Curves_proto::Piecewise_polynomial_curve::InitAsDefaultInstance();
+}
+
+void InitDefaultsPiecewise_polynomial_curve() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &InitDefaultsPiecewise_polynomial_curveImpl);
+}
+
+::google::protobuf::Metadata file_level_metadata[2];
+
+const ::google::protobuf::uint32 TableStruct::offsets[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
+  ~0u,  // no _has_bits_
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Curves_proto::Matrix, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Curves_proto::Matrix, rows_),
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Curves_proto::Matrix, cols_),
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Curves_proto::Matrix, data_),
+  ~0u,  // no _has_bits_
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Curves_proto::Piecewise_polynomial_curve, _internal_metadata_),
+  ~0u,  // no _extensions_
+  ~0u,  // no _oneof_case_
+  ~0u,  // no _weak_field_map_
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Curves_proto::Piecewise_polynomial_curve, number_of_curves_),
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Curves_proto::Piecewise_polynomial_curve, dimension_),
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Curves_proto::Piecewise_polynomial_curve, time_),
+  GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(::Curves_proto::Piecewise_polynomial_curve, curves_),
+};
+static const ::google::protobuf::internal::MigrationSchema schemas[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
+  { 0, -1, sizeof(::Curves_proto::Matrix)},
+  { 8, -1, sizeof(::Curves_proto::Piecewise_polynomial_curve)},
+};
+
+static ::google::protobuf::Message const * const file_default_instances[] = {
+  reinterpret_cast<const ::google::protobuf::Message*>(&::Curves_proto::_Matrix_default_instance_),
+  reinterpret_cast<const ::google::protobuf::Message*>(&::Curves_proto::_Piecewise_polynomial_curve_default_instance_),
+};
+
+void protobuf_AssignDescriptors() {
+  AddDescriptors();
+  ::google::protobuf::MessageFactory* factory = NULL;
+  AssignDescriptors(
+      "Curves_proto.proto", schemas, file_default_instances, TableStruct::offsets, factory,
+      file_level_metadata, NULL, NULL);
+}
+
+void protobuf_AssignDescriptorsOnce() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &protobuf_AssignDescriptors);
+}
+
+void protobuf_RegisterTypes(const ::std::string&) GOOGLE_PROTOBUF_ATTRIBUTE_COLD;
+void protobuf_RegisterTypes(const ::std::string&) {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::internal::RegisterAllTypes(file_level_metadata, 2);
+}
+
+void AddDescriptorsImpl() {
+  InitDefaults();
+  static const char descriptor[] GOOGLE_PROTOBUF_ATTRIBUTE_SECTION_VARIABLE(protodesc_cold) = {
+      "\n\022Curves_proto.proto\022\014Curves_proto\"6\n\006Ma"
+      "trix\022\014\n\004rows\030\001 \001(\r\022\014\n\004cols\030\002 \001(\r\022\020\n\004data"
+      "\030\003 \003(\001B\002\020\001\"\201\001\n\032Piecewise_polynomial_curv"
+      "e\022\030\n\020number_of_curves\030\001 \001(\r\022\021\n\tdimension"
+      "\030\002 \001(\r\022\020\n\004time\030\003 \003(\001B\002\020\001\022$\n\006curves\030\004 \003(\013"
+      "2\024.Curves_proto.Matrixb\006proto3"
+  };
+  ::google::protobuf::DescriptorPool::InternalAddGeneratedFile(
+      descriptor, 230);
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
+    "Curves_proto.proto", &protobuf_RegisterTypes);
+}
+
+void AddDescriptors() {
+  static GOOGLE_PROTOBUF_DECLARE_ONCE(once);
+  ::google::protobuf::GoogleOnceInit(&once, &AddDescriptorsImpl);
+}
+// Force AddDescriptors() to be called at dynamic initialization time.
+struct StaticDescriptorInitializer {
+  StaticDescriptorInitializer() {
+    AddDescriptors();
+  }
+} static_descriptor_initializer;
+}  // namespace protobuf_Curves_5fproto_2eproto
+namespace Curves_proto {
+
+// ===================================================================
+
+void Matrix::InitAsDefaultInstance() {
+}
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Matrix::kRowsFieldNumber;
+const int Matrix::kColsFieldNumber;
+const int Matrix::kDataFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Matrix::Matrix()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
+    ::protobuf_Curves_5fproto_2eproto::InitDefaultsMatrix();
+  }
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:Curves_proto.Matrix)
+}
+Matrix::Matrix(const Matrix& from)
+  : ::google::protobuf::Message(),
+      _internal_metadata_(NULL),
+      data_(from.data_),
+      _cached_size_(0) {
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  ::memcpy(&rows_, &from.rows_,
+    static_cast<size_t>(reinterpret_cast<char*>(&cols_) -
+    reinterpret_cast<char*>(&rows_)) + sizeof(cols_));
+  // @@protoc_insertion_point(copy_constructor:Curves_proto.Matrix)
+}
+
+void Matrix::SharedCtor() {
+  ::memset(&rows_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&cols_) -
+      reinterpret_cast<char*>(&rows_)) + sizeof(cols_));
+  _cached_size_ = 0;
+}
+
+Matrix::~Matrix() {
+  // @@protoc_insertion_point(destructor:Curves_proto.Matrix)
+  SharedDtor();
+}
+
+void Matrix::SharedDtor() {
+}
+
+void Matrix::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Matrix::descriptor() {
+  ::protobuf_Curves_5fproto_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_Curves_5fproto_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
+}
+
+const Matrix& Matrix::default_instance() {
+  ::protobuf_Curves_5fproto_2eproto::InitDefaultsMatrix();
+  return *internal_default_instance();
+}
+
+Matrix* Matrix::New(::google::protobuf::Arena* arena) const {
+  Matrix* n = new Matrix;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Matrix::Clear() {
+// @@protoc_insertion_point(message_clear_start:Curves_proto.Matrix)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  data_.Clear();
+  ::memset(&rows_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&cols_) -
+      reinterpret_cast<char*>(&rows_)) + sizeof(cols_));
+  _internal_metadata_.Clear();
+}
+
+bool Matrix::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:Curves_proto.Matrix)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // uint32 rows = 1;
+      case 1: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(8u /* 8 & 0xFF */)) {
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &rows_)));
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      // uint32 cols = 2;
+      case 2: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(16u /* 16 & 0xFF */)) {
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &cols_)));
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      // repeated double data = 3 [packed = true];
+      case 3: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(26u /* 26 & 0xFF */)) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
+                 input, this->mutable_data())));
+        } else if (
+            static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(25u /* 25 & 0xFF */)) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
+                 1, 26u, input, this->mutable_data())));
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, _internal_metadata_.mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:Curves_proto.Matrix)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:Curves_proto.Matrix)
+  return false;
+#undef DO_
+}
+
+void Matrix::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:Curves_proto.Matrix)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // uint32 rows = 1;
+  if (this->rows() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->rows(), output);
+  }
+
+  // uint32 cols = 2;
+  if (this->cols() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(2, this->cols(), output);
+  }
+
+  // repeated double data = 3 [packed = true];
+  if (this->data_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(3, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(static_cast< ::google::protobuf::uint32>(
+        _data_cached_byte_size_));
+    ::google::protobuf::internal::WireFormatLite::WriteDoubleArray(
+      this->data().data(), this->data_size(), output);
+  }
+
+  if ((_internal_metadata_.have_unknown_fields() &&  ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        (::google::protobuf::internal::GetProto3PreserveUnknownsDefault()   ? _internal_metadata_.unknown_fields()   : _internal_metadata_.default_instance()), output);
+  }
+  // @@protoc_insertion_point(serialize_end:Curves_proto.Matrix)
+}
+
+::google::protobuf::uint8* Matrix::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:Curves_proto.Matrix)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // uint32 rows = 1;
+  if (this->rows() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->rows(), target);
+  }
+
+  // uint32 cols = 2;
+  if (this->cols() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(2, this->cols(), target);
+  }
+
+  // repeated double data = 3 [packed = true];
+  if (this->data_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      3,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+        static_cast< ::google::protobuf::int32>(
+            _data_cached_byte_size_), target);
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteDoubleNoTagToArray(this->data_, target);
+  }
+
+  if ((_internal_metadata_.have_unknown_fields() &&  ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        (::google::protobuf::internal::GetProto3PreserveUnknownsDefault()   ? _internal_metadata_.unknown_fields()   : _internal_metadata_.default_instance()), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:Curves_proto.Matrix)
+  return target;
+}
+
+size_t Matrix::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:Curves_proto.Matrix)
+  size_t total_size = 0;
+
+  if ((_internal_metadata_.have_unknown_fields() &&  ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        (::google::protobuf::internal::GetProto3PreserveUnknownsDefault()   ? _internal_metadata_.unknown_fields()   : _internal_metadata_.default_instance()));
+  }
+  // repeated double data = 3 [packed = true];
+  {
+    unsigned int count = static_cast<unsigned int>(this->data_size());
+    size_t data_size = 8UL * count;
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+            static_cast< ::google::protobuf::int32>(data_size));
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _data_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // uint32 rows = 1;
+  if (this->rows() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->rows());
+  }
+
+  // uint32 cols = 2;
+  if (this->cols() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->cols());
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Matrix::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:Curves_proto.Matrix)
+  GOOGLE_DCHECK_NE(&from, this);
+  const Matrix* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const Matrix>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Curves_proto.Matrix)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Curves_proto.Matrix)
+    MergeFrom(*source);
+  }
+}
+
+void Matrix::MergeFrom(const Matrix& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:Curves_proto.Matrix)
+  GOOGLE_DCHECK_NE(&from, this);
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  data_.MergeFrom(from.data_);
+  if (from.rows() != 0) {
+    set_rows(from.rows());
+  }
+  if (from.cols() != 0) {
+    set_cols(from.cols());
+  }
+}
+
+void Matrix::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Curves_proto.Matrix)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Matrix::CopyFrom(const Matrix& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Curves_proto.Matrix)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Matrix::IsInitialized() const {
+  return true;
+}
+
+void Matrix::Swap(Matrix* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Matrix::InternalSwap(Matrix* other) {
+  using std::swap;
+  data_.InternalSwap(&other->data_);
+  swap(rows_, other->rows_);
+  swap(cols_, other->cols_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Matrix::GetMetadata() const {
+  protobuf_Curves_5fproto_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_Curves_5fproto_2eproto::file_level_metadata[kIndexInFileMessages];
+}
+
+
+// ===================================================================
+
+void Piecewise_polynomial_curve::InitAsDefaultInstance() {
+}
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int Piecewise_polynomial_curve::kNumberOfCurvesFieldNumber;
+const int Piecewise_polynomial_curve::kDimensionFieldNumber;
+const int Piecewise_polynomial_curve::kTimeFieldNumber;
+const int Piecewise_polynomial_curve::kCurvesFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+Piecewise_polynomial_curve::Piecewise_polynomial_curve()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  if (GOOGLE_PREDICT_TRUE(this != internal_default_instance())) {
+    ::protobuf_Curves_5fproto_2eproto::InitDefaultsPiecewise_polynomial_curve();
+  }
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:Curves_proto.Piecewise_polynomial_curve)
+}
+Piecewise_polynomial_curve::Piecewise_polynomial_curve(const Piecewise_polynomial_curve& from)
+  : ::google::protobuf::Message(),
+      _internal_metadata_(NULL),
+      time_(from.time_),
+      curves_(from.curves_),
+      _cached_size_(0) {
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  ::memcpy(&number_of_curves_, &from.number_of_curves_,
+    static_cast<size_t>(reinterpret_cast<char*>(&dimension_) -
+    reinterpret_cast<char*>(&number_of_curves_)) + sizeof(dimension_));
+  // @@protoc_insertion_point(copy_constructor:Curves_proto.Piecewise_polynomial_curve)
+}
+
+void Piecewise_polynomial_curve::SharedCtor() {
+  ::memset(&number_of_curves_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&dimension_) -
+      reinterpret_cast<char*>(&number_of_curves_)) + sizeof(dimension_));
+  _cached_size_ = 0;
+}
+
+Piecewise_polynomial_curve::~Piecewise_polynomial_curve() {
+  // @@protoc_insertion_point(destructor:Curves_proto.Piecewise_polynomial_curve)
+  SharedDtor();
+}
+
+void Piecewise_polynomial_curve::SharedDtor() {
+}
+
+void Piecewise_polynomial_curve::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* Piecewise_polynomial_curve::descriptor() {
+  ::protobuf_Curves_5fproto_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_Curves_5fproto_2eproto::file_level_metadata[kIndexInFileMessages].descriptor;
+}
+
+const Piecewise_polynomial_curve& Piecewise_polynomial_curve::default_instance() {
+  ::protobuf_Curves_5fproto_2eproto::InitDefaultsPiecewise_polynomial_curve();
+  return *internal_default_instance();
+}
+
+Piecewise_polynomial_curve* Piecewise_polynomial_curve::New(::google::protobuf::Arena* arena) const {
+  Piecewise_polynomial_curve* n = new Piecewise_polynomial_curve;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void Piecewise_polynomial_curve::Clear() {
+// @@protoc_insertion_point(message_clear_start:Curves_proto.Piecewise_polynomial_curve)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  // Prevent compiler warnings about cached_has_bits being unused
+  (void) cached_has_bits;
+
+  time_.Clear();
+  curves_.Clear();
+  ::memset(&number_of_curves_, 0, static_cast<size_t>(
+      reinterpret_cast<char*>(&dimension_) -
+      reinterpret_cast<char*>(&number_of_curves_)) + sizeof(dimension_));
+  _internal_metadata_.Clear();
+}
+
+bool Piecewise_polynomial_curve::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:Curves_proto.Piecewise_polynomial_curve)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoffNoLastTag(127u);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // uint32 number_of_curves = 1;
+      case 1: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(8u /* 8 & 0xFF */)) {
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &number_of_curves_)));
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      // uint32 dimension = 2;
+      case 2: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(16u /* 16 & 0xFF */)) {
+
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>(
+                 input, &dimension_)));
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      // repeated double time = 3 [packed = true];
+      case 3: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(26u /* 26 & 0xFF */)) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive<
+                   double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
+                 input, this->mutable_time())));
+        } else if (
+            static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(25u /* 25 & 0xFF */)) {
+          DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline<
+                   double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>(
+                 1, 26u, input, this->mutable_time())));
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      // repeated .Curves_proto.Matrix curves = 4;
+      case 4: {
+        if (static_cast< ::google::protobuf::uint8>(tag) ==
+            static_cast< ::google::protobuf::uint8>(34u /* 34 & 0xFF */)) {
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessage(input, add_curves()));
+        } else {
+          goto handle_unusual;
+        }
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0) {
+          goto success;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, _internal_metadata_.mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:Curves_proto.Piecewise_polynomial_curve)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:Curves_proto.Piecewise_polynomial_curve)
+  return false;
+#undef DO_
+}
+
+void Piecewise_polynomial_curve::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:Curves_proto.Piecewise_polynomial_curve)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // uint32 number_of_curves = 1;
+  if (this->number_of_curves() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(1, this->number_of_curves(), output);
+  }
+
+  // uint32 dimension = 2;
+  if (this->dimension() != 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteUInt32(2, this->dimension(), output);
+  }
+
+  // repeated double time = 3 [packed = true];
+  if (this->time_size() > 0) {
+    ::google::protobuf::internal::WireFormatLite::WriteTag(3, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output);
+    output->WriteVarint32(static_cast< ::google::protobuf::uint32>(
+        _time_cached_byte_size_));
+    ::google::protobuf::internal::WireFormatLite::WriteDoubleArray(
+      this->time().data(), this->time_size(), output);
+  }
+
+  // repeated .Curves_proto.Matrix curves = 4;
+  for (unsigned int i = 0,
+      n = static_cast<unsigned int>(this->curves_size()); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      4, this->curves(static_cast<int>(i)), output);
+  }
+
+  if ((_internal_metadata_.have_unknown_fields() &&  ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        (::google::protobuf::internal::GetProto3PreserveUnknownsDefault()   ? _internal_metadata_.unknown_fields()   : _internal_metadata_.default_instance()), output);
+  }
+  // @@protoc_insertion_point(serialize_end:Curves_proto.Piecewise_polynomial_curve)
+}
+
+::google::protobuf::uint8* Piecewise_polynomial_curve::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  (void)deterministic; // Unused
+  // @@protoc_insertion_point(serialize_to_array_start:Curves_proto.Piecewise_polynomial_curve)
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  // uint32 number_of_curves = 1;
+  if (this->number_of_curves() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(1, this->number_of_curves(), target);
+  }
+
+  // uint32 dimension = 2;
+  if (this->dimension() != 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(2, this->dimension(), target);
+  }
+
+  // repeated double time = 3 [packed = true];
+  if (this->time_size() > 0) {
+    target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray(
+      3,
+      ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+      target);
+    target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray(
+        static_cast< ::google::protobuf::int32>(
+            _time_cached_byte_size_), target);
+    target = ::google::protobuf::internal::WireFormatLite::
+      WriteDoubleNoTagToArray(this->time_, target);
+  }
+
+  // repeated .Curves_proto.Matrix curves = 4;
+  for (unsigned int i = 0,
+      n = static_cast<unsigned int>(this->curves_size()); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageToArray(
+        4, this->curves(static_cast<int>(i)), deterministic, target);
+  }
+
+  if ((_internal_metadata_.have_unknown_fields() &&  ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        (::google::protobuf::internal::GetProto3PreserveUnknownsDefault()   ? _internal_metadata_.unknown_fields()   : _internal_metadata_.default_instance()), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:Curves_proto.Piecewise_polynomial_curve)
+  return target;
+}
+
+size_t Piecewise_polynomial_curve::ByteSizeLong() const {
+// @@protoc_insertion_point(message_byte_size_start:Curves_proto.Piecewise_polynomial_curve)
+  size_t total_size = 0;
+
+  if ((_internal_metadata_.have_unknown_fields() &&  ::google::protobuf::internal::GetProto3PreserveUnknownsDefault())) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        (::google::protobuf::internal::GetProto3PreserveUnknownsDefault()   ? _internal_metadata_.unknown_fields()   : _internal_metadata_.default_instance()));
+  }
+  // repeated double time = 3 [packed = true];
+  {
+    unsigned int count = static_cast<unsigned int>(this->time_size());
+    size_t data_size = 8UL * count;
+    if (data_size > 0) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+            static_cast< ::google::protobuf::int32>(data_size));
+    }
+    int cached_size = ::google::protobuf::internal::ToCachedSize(data_size);
+    GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+    _time_cached_byte_size_ = cached_size;
+    GOOGLE_SAFE_CONCURRENT_WRITES_END();
+    total_size += data_size;
+  }
+
+  // repeated .Curves_proto.Matrix curves = 4;
+  {
+    unsigned int count = static_cast<unsigned int>(this->curves_size());
+    total_size += 1UL * count;
+    for (unsigned int i = 0; i < count; i++) {
+      total_size +=
+        ::google::protobuf::internal::WireFormatLite::MessageSize(
+          this->curves(static_cast<int>(i)));
+    }
+  }
+
+  // uint32 number_of_curves = 1;
+  if (this->number_of_curves() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->number_of_curves());
+  }
+
+  // uint32 dimension = 2;
+  if (this->dimension() != 0) {
+    total_size += 1 +
+      ::google::protobuf::internal::WireFormatLite::UInt32Size(
+        this->dimension());
+  }
+
+  int cached_size = ::google::protobuf::internal::ToCachedSize(total_size);
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = cached_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void Piecewise_polynomial_curve::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:Curves_proto.Piecewise_polynomial_curve)
+  GOOGLE_DCHECK_NE(&from, this);
+  const Piecewise_polynomial_curve* source =
+      ::google::protobuf::internal::DynamicCastToGenerated<const Piecewise_polynomial_curve>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:Curves_proto.Piecewise_polynomial_curve)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:Curves_proto.Piecewise_polynomial_curve)
+    MergeFrom(*source);
+  }
+}
+
+void Piecewise_polynomial_curve::MergeFrom(const Piecewise_polynomial_curve& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:Curves_proto.Piecewise_polynomial_curve)
+  GOOGLE_DCHECK_NE(&from, this);
+  _internal_metadata_.MergeFrom(from._internal_metadata_);
+  ::google::protobuf::uint32 cached_has_bits = 0;
+  (void) cached_has_bits;
+
+  time_.MergeFrom(from.time_);
+  curves_.MergeFrom(from.curves_);
+  if (from.number_of_curves() != 0) {
+    set_number_of_curves(from.number_of_curves());
+  }
+  if (from.dimension() != 0) {
+    set_dimension(from.dimension());
+  }
+}
+
+void Piecewise_polynomial_curve::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:Curves_proto.Piecewise_polynomial_curve)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void Piecewise_polynomial_curve::CopyFrom(const Piecewise_polynomial_curve& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:Curves_proto.Piecewise_polynomial_curve)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool Piecewise_polynomial_curve::IsInitialized() const {
+  return true;
+}
+
+void Piecewise_polynomial_curve::Swap(Piecewise_polynomial_curve* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void Piecewise_polynomial_curve::InternalSwap(Piecewise_polynomial_curve* other) {
+  using std::swap;
+  time_.InternalSwap(&other->time_);
+  curves_.InternalSwap(&other->curves_);
+  swap(number_of_curves_, other->number_of_curves_);
+  swap(dimension_, other->dimension_);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  swap(_cached_size_, other->_cached_size_);
+}
+
+::google::protobuf::Metadata Piecewise_polynomial_curve::GetMetadata() const {
+  protobuf_Curves_5fproto_2eproto::protobuf_AssignDescriptorsOnce();
+  return ::protobuf_Curves_5fproto_2eproto::file_level_metadata[kIndexInFileMessages];
+}
+
+
+// @@protoc_insertion_point(namespace_scope)
+}  // namespace Curves_proto
+
+// @@protoc_insertion_point(global_scope)
diff --git a/include/curves/proto/Curves_proto.pb.h b/include/curves/proto/Curves_proto.pb.h
new file mode 100644
index 0000000..53fdc09
--- /dev/null
+++ b/include/curves/proto/Curves_proto.pb.h
@@ -0,0 +1,490 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: Curves_proto.proto
+
+#ifndef PROTOBUF_Curves_5fproto_2eproto__INCLUDED
+#define PROTOBUF_Curves_5fproto_2eproto__INCLUDED
+
+#include <string>
+
+#include <google/protobuf/stubs/common.h>
+
+#if GOOGLE_PROTOBUF_VERSION < 3005000
+#error This file was generated by a newer version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please update
+#error your headers.
+#endif
+#if 3005001 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#error This file was generated by an older version of protoc which is
+#error incompatible with your Protocol Buffer headers.  Please
+#error regenerate this file with a newer version of protoc.
+#endif
+
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/arena.h>
+#include <google/protobuf/arenastring.h>
+#include <google/protobuf/generated_message_table_driven.h>
+#include <google/protobuf/generated_message_util.h>
+#include <google/protobuf/metadata.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/repeated_field.h>  // IWYU pragma: export
+#include <google/protobuf/extension_set.h>  // IWYU pragma: export
+#include <google/protobuf/unknown_field_set.h>
+// @@protoc_insertion_point(includes)
+
+namespace protobuf_Curves_5fproto_2eproto {
+// Internal implementation detail -- do not use these members.
+struct TableStruct {
+  static const ::google::protobuf::internal::ParseTableField entries[];
+  static const ::google::protobuf::internal::AuxillaryParseTableField aux[];
+  static const ::google::protobuf::internal::ParseTable schema[2];
+  static const ::google::protobuf::internal::FieldMetadata field_metadata[];
+  static const ::google::protobuf::internal::SerializationTable serialization_table[];
+  static const ::google::protobuf::uint32 offsets[];
+};
+void AddDescriptors();
+void InitDefaultsMatrixImpl();
+void InitDefaultsMatrix();
+void InitDefaultsPiecewise_polynomial_curveImpl();
+void InitDefaultsPiecewise_polynomial_curve();
+inline void InitDefaults() {
+  InitDefaultsMatrix();
+  InitDefaultsPiecewise_polynomial_curve();
+}
+}  // namespace protobuf_Curves_5fproto_2eproto
+namespace Curves_proto {
+class Matrix;
+class MatrixDefaultTypeInternal;
+extern MatrixDefaultTypeInternal _Matrix_default_instance_;
+class Piecewise_polynomial_curve;
+class Piecewise_polynomial_curveDefaultTypeInternal;
+extern Piecewise_polynomial_curveDefaultTypeInternal _Piecewise_polynomial_curve_default_instance_;
+}  // namespace Curves_proto
+namespace Curves_proto {
+
+// ===================================================================
+
+class Matrix : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Curves_proto.Matrix) */ {
+ public:
+  Matrix();
+  virtual ~Matrix();
+
+  Matrix(const Matrix& from);
+
+  inline Matrix& operator=(const Matrix& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  #if LANG_CXX11
+  Matrix(Matrix&& from) noexcept
+    : Matrix() {
+    *this = ::std::move(from);
+  }
+
+  inline Matrix& operator=(Matrix&& from) noexcept {
+    if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
+      if (this != &from) InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+  #endif
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Matrix& default_instance();
+
+  static void InitAsDefaultInstance();  // FOR INTERNAL USE ONLY
+  static inline const Matrix* internal_default_instance() {
+    return reinterpret_cast<const Matrix*>(
+               &_Matrix_default_instance_);
+  }
+  static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
+    0;
+
+  void Swap(Matrix* other);
+  friend void swap(Matrix& a, Matrix& b) {
+    a.Swap(&b);
+  }
+
+  // implements Message ----------------------------------------------
+
+  inline Matrix* New() const PROTOBUF_FINAL { return New(NULL); }
+
+  Matrix* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void CopyFrom(const Matrix& from);
+  void MergeFrom(const Matrix& from);
+  void Clear() PROTOBUF_FINAL;
+  bool IsInitialized() const PROTOBUF_FINAL;
+
+  size_t ByteSizeLong() const PROTOBUF_FINAL;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const PROTOBUF_FINAL;
+  void InternalSwap(Matrix* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return NULL;
+  }
+  inline void* MaybeArenaPtr() const {
+    return NULL;
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated double data = 3 [packed = true];
+  int data_size() const;
+  void clear_data();
+  static const int kDataFieldNumber = 3;
+  double data(int index) const;
+  void set_data(int index, double value);
+  void add_data(double value);
+  const ::google::protobuf::RepeatedField< double >&
+      data() const;
+  ::google::protobuf::RepeatedField< double >*
+      mutable_data();
+
+  // uint32 rows = 1;
+  void clear_rows();
+  static const int kRowsFieldNumber = 1;
+  ::google::protobuf::uint32 rows() const;
+  void set_rows(::google::protobuf::uint32 value);
+
+  // uint32 cols = 2;
+  void clear_cols();
+  static const int kColsFieldNumber = 2;
+  ::google::protobuf::uint32 cols() const;
+  void set_cols(::google::protobuf::uint32 value);
+
+  // @@protoc_insertion_point(class_scope:Curves_proto.Matrix)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::RepeatedField< double > data_;
+  mutable int _data_cached_byte_size_;
+  ::google::protobuf::uint32 rows_;
+  ::google::protobuf::uint32 cols_;
+  mutable int _cached_size_;
+  friend struct ::protobuf_Curves_5fproto_2eproto::TableStruct;
+  friend void ::protobuf_Curves_5fproto_2eproto::InitDefaultsMatrixImpl();
+};
+// -------------------------------------------------------------------
+
+class Piecewise_polynomial_curve : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:Curves_proto.Piecewise_polynomial_curve) */ {
+ public:
+  Piecewise_polynomial_curve();
+  virtual ~Piecewise_polynomial_curve();
+
+  Piecewise_polynomial_curve(const Piecewise_polynomial_curve& from);
+
+  inline Piecewise_polynomial_curve& operator=(const Piecewise_polynomial_curve& from) {
+    CopyFrom(from);
+    return *this;
+  }
+  #if LANG_CXX11
+  Piecewise_polynomial_curve(Piecewise_polynomial_curve&& from) noexcept
+    : Piecewise_polynomial_curve() {
+    *this = ::std::move(from);
+  }
+
+  inline Piecewise_polynomial_curve& operator=(Piecewise_polynomial_curve&& from) noexcept {
+    if (GetArenaNoVirtual() == from.GetArenaNoVirtual()) {
+      if (this != &from) InternalSwap(&from);
+    } else {
+      CopyFrom(from);
+    }
+    return *this;
+  }
+  #endif
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const Piecewise_polynomial_curve& default_instance();
+
+  static void InitAsDefaultInstance();  // FOR INTERNAL USE ONLY
+  static inline const Piecewise_polynomial_curve* internal_default_instance() {
+    return reinterpret_cast<const Piecewise_polynomial_curve*>(
+               &_Piecewise_polynomial_curve_default_instance_);
+  }
+  static PROTOBUF_CONSTEXPR int const kIndexInFileMessages =
+    1;
+
+  void Swap(Piecewise_polynomial_curve* other);
+  friend void swap(Piecewise_polynomial_curve& a, Piecewise_polynomial_curve& b) {
+    a.Swap(&b);
+  }
+
+  // implements Message ----------------------------------------------
+
+  inline Piecewise_polynomial_curve* New() const PROTOBUF_FINAL { return New(NULL); }
+
+  Piecewise_polynomial_curve* New(::google::protobuf::Arena* arena) const PROTOBUF_FINAL;
+  void CopyFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void MergeFrom(const ::google::protobuf::Message& from) PROTOBUF_FINAL;
+  void CopyFrom(const Piecewise_polynomial_curve& from);
+  void MergeFrom(const Piecewise_polynomial_curve& from);
+  void Clear() PROTOBUF_FINAL;
+  bool IsInitialized() const PROTOBUF_FINAL;
+
+  size_t ByteSizeLong() const PROTOBUF_FINAL;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input) PROTOBUF_FINAL;
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const PROTOBUF_FINAL;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* target) const PROTOBUF_FINAL;
+  int GetCachedSize() const PROTOBUF_FINAL { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const PROTOBUF_FINAL;
+  void InternalSwap(Piecewise_polynomial_curve* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return NULL;
+  }
+  inline void* MaybeArenaPtr() const {
+    return NULL;
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const PROTOBUF_FINAL;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated double time = 3 [packed = true];
+  int time_size() const;
+  void clear_time();
+  static const int kTimeFieldNumber = 3;
+  double time(int index) const;
+  void set_time(int index, double value);
+  void add_time(double value);
+  const ::google::protobuf::RepeatedField< double >&
+      time() const;
+  ::google::protobuf::RepeatedField< double >*
+      mutable_time();
+
+  // repeated .Curves_proto.Matrix curves = 4;
+  int curves_size() const;
+  void clear_curves();
+  static const int kCurvesFieldNumber = 4;
+  const ::Curves_proto::Matrix& curves(int index) const;
+  ::Curves_proto::Matrix* mutable_curves(int index);
+  ::Curves_proto::Matrix* add_curves();
+  ::google::protobuf::RepeatedPtrField< ::Curves_proto::Matrix >*
+      mutable_curves();
+  const ::google::protobuf::RepeatedPtrField< ::Curves_proto::Matrix >&
+      curves() const;
+
+  // uint32 number_of_curves = 1;
+  void clear_number_of_curves();
+  static const int kNumberOfCurvesFieldNumber = 1;
+  ::google::protobuf::uint32 number_of_curves() const;
+  void set_number_of_curves(::google::protobuf::uint32 value);
+
+  // uint32 dimension = 2;
+  void clear_dimension();
+  static const int kDimensionFieldNumber = 2;
+  ::google::protobuf::uint32 dimension() const;
+  void set_dimension(::google::protobuf::uint32 value);
+
+  // @@protoc_insertion_point(class_scope:Curves_proto.Piecewise_polynomial_curve)
+ private:
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::RepeatedField< double > time_;
+  mutable int _time_cached_byte_size_;
+  ::google::protobuf::RepeatedPtrField< ::Curves_proto::Matrix > curves_;
+  ::google::protobuf::uint32 number_of_curves_;
+  ::google::protobuf::uint32 dimension_;
+  mutable int _cached_size_;
+  friend struct ::protobuf_Curves_5fproto_2eproto::TableStruct;
+  friend void ::protobuf_Curves_5fproto_2eproto::InitDefaultsPiecewise_polynomial_curveImpl();
+};
+// ===================================================================
+
+
+// ===================================================================
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+  #pragma GCC diagnostic push
+  #pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif  // __GNUC__
+// Matrix
+
+// uint32 rows = 1;
+inline void Matrix::clear_rows() {
+  rows_ = 0u;
+}
+inline ::google::protobuf::uint32 Matrix::rows() const {
+  // @@protoc_insertion_point(field_get:Curves_proto.Matrix.rows)
+  return rows_;
+}
+inline void Matrix::set_rows(::google::protobuf::uint32 value) {
+  
+  rows_ = value;
+  // @@protoc_insertion_point(field_set:Curves_proto.Matrix.rows)
+}
+
+// uint32 cols = 2;
+inline void Matrix::clear_cols() {
+  cols_ = 0u;
+}
+inline ::google::protobuf::uint32 Matrix::cols() const {
+  // @@protoc_insertion_point(field_get:Curves_proto.Matrix.cols)
+  return cols_;
+}
+inline void Matrix::set_cols(::google::protobuf::uint32 value) {
+  
+  cols_ = value;
+  // @@protoc_insertion_point(field_set:Curves_proto.Matrix.cols)
+}
+
+// repeated double data = 3 [packed = true];
+inline int Matrix::data_size() const {
+  return data_.size();
+}
+inline void Matrix::clear_data() {
+  data_.Clear();
+}
+inline double Matrix::data(int index) const {
+  // @@protoc_insertion_point(field_get:Curves_proto.Matrix.data)
+  return data_.Get(index);
+}
+inline void Matrix::set_data(int index, double value) {
+  data_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Curves_proto.Matrix.data)
+}
+inline void Matrix::add_data(double value) {
+  data_.Add(value);
+  // @@protoc_insertion_point(field_add:Curves_proto.Matrix.data)
+}
+inline const ::google::protobuf::RepeatedField< double >&
+Matrix::data() const {
+  // @@protoc_insertion_point(field_list:Curves_proto.Matrix.data)
+  return data_;
+}
+inline ::google::protobuf::RepeatedField< double >*
+Matrix::mutable_data() {
+  // @@protoc_insertion_point(field_mutable_list:Curves_proto.Matrix.data)
+  return &data_;
+}
+
+// -------------------------------------------------------------------
+
+// Piecewise_polynomial_curve
+
+// uint32 number_of_curves = 1;
+inline void Piecewise_polynomial_curve::clear_number_of_curves() {
+  number_of_curves_ = 0u;
+}
+inline ::google::protobuf::uint32 Piecewise_polynomial_curve::number_of_curves() const {
+  // @@protoc_insertion_point(field_get:Curves_proto.Piecewise_polynomial_curve.number_of_curves)
+  return number_of_curves_;
+}
+inline void Piecewise_polynomial_curve::set_number_of_curves(::google::protobuf::uint32 value) {
+  
+  number_of_curves_ = value;
+  // @@protoc_insertion_point(field_set:Curves_proto.Piecewise_polynomial_curve.number_of_curves)
+}
+
+// uint32 dimension = 2;
+inline void Piecewise_polynomial_curve::clear_dimension() {
+  dimension_ = 0u;
+}
+inline ::google::protobuf::uint32 Piecewise_polynomial_curve::dimension() const {
+  // @@protoc_insertion_point(field_get:Curves_proto.Piecewise_polynomial_curve.dimension)
+  return dimension_;
+}
+inline void Piecewise_polynomial_curve::set_dimension(::google::protobuf::uint32 value) {
+  
+  dimension_ = value;
+  // @@protoc_insertion_point(field_set:Curves_proto.Piecewise_polynomial_curve.dimension)
+}
+
+// repeated double time = 3 [packed = true];
+inline int Piecewise_polynomial_curve::time_size() const {
+  return time_.size();
+}
+inline void Piecewise_polynomial_curve::clear_time() {
+  time_.Clear();
+}
+inline double Piecewise_polynomial_curve::time(int index) const {
+  // @@protoc_insertion_point(field_get:Curves_proto.Piecewise_polynomial_curve.time)
+  return time_.Get(index);
+}
+inline void Piecewise_polynomial_curve::set_time(int index, double value) {
+  time_.Set(index, value);
+  // @@protoc_insertion_point(field_set:Curves_proto.Piecewise_polynomial_curve.time)
+}
+inline void Piecewise_polynomial_curve::add_time(double value) {
+  time_.Add(value);
+  // @@protoc_insertion_point(field_add:Curves_proto.Piecewise_polynomial_curve.time)
+}
+inline const ::google::protobuf::RepeatedField< double >&
+Piecewise_polynomial_curve::time() const {
+  // @@protoc_insertion_point(field_list:Curves_proto.Piecewise_polynomial_curve.time)
+  return time_;
+}
+inline ::google::protobuf::RepeatedField< double >*
+Piecewise_polynomial_curve::mutable_time() {
+  // @@protoc_insertion_point(field_mutable_list:Curves_proto.Piecewise_polynomial_curve.time)
+  return &time_;
+}
+
+// repeated .Curves_proto.Matrix curves = 4;
+inline int Piecewise_polynomial_curve::curves_size() const {
+  return curves_.size();
+}
+inline void Piecewise_polynomial_curve::clear_curves() {
+  curves_.Clear();
+}
+inline const ::Curves_proto::Matrix& Piecewise_polynomial_curve::curves(int index) const {
+  // @@protoc_insertion_point(field_get:Curves_proto.Piecewise_polynomial_curve.curves)
+  return curves_.Get(index);
+}
+inline ::Curves_proto::Matrix* Piecewise_polynomial_curve::mutable_curves(int index) {
+  // @@protoc_insertion_point(field_mutable:Curves_proto.Piecewise_polynomial_curve.curves)
+  return curves_.Mutable(index);
+}
+inline ::Curves_proto::Matrix* Piecewise_polynomial_curve::add_curves() {
+  // @@protoc_insertion_point(field_add:Curves_proto.Piecewise_polynomial_curve.curves)
+  return curves_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::Curves_proto::Matrix >*
+Piecewise_polynomial_curve::mutable_curves() {
+  // @@protoc_insertion_point(field_mutable_list:Curves_proto.Piecewise_polynomial_curve.curves)
+  return &curves_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::Curves_proto::Matrix >&
+Piecewise_polynomial_curve::curves() const {
+  // @@protoc_insertion_point(field_list:Curves_proto.Piecewise_polynomial_curve.curves)
+  return curves_;
+}
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+  #pragma GCC diagnostic pop
+#endif  // __GNUC__
+// -------------------------------------------------------------------
+
+
+// @@protoc_insertion_point(namespace_scope)
+
+}  // namespace Curves_proto
+
+// @@protoc_insertion_point(global_scope)
+
+#endif  // PROTOBUF_Curves_5fproto_2eproto__INCLUDED
diff --git a/include/curves/proto/Curves_proto.proto b/include/curves/proto/Curves_proto.proto
new file mode 100644
index 0000000..f029b63
--- /dev/null
+++ b/include/curves/proto/Curves_proto.proto
@@ -0,0 +1,22 @@
+syntax = "proto3";
+
+package Curves_proto;
+
+message Matrix {
+	uint32 rows = 1; // Total number of rows
+	uint32 cols = 2; // Total number of columns
+	// Array of coeffs can be seen as a matrix : data[col*rows+row]
+	repeated double data = 3 [packed=true];
+}
+
+message Piecewise_polynomial_curve {
+	uint32 number_of_curves = 1; // Total number of curves (segments)
+	uint32 dimension = 2; // Size of dimension
+
+	// Array of times : time[j]
+	// With j<=number_of_curves
+	repeated double time = 3 [packed=true];
+
+	repeated Matrix curves = 4;
+};
+
diff --git a/tests/Main.cpp b/tests/Main.cpp
index 1cdc57b..a43ef75 100644
--- a/tests/Main.cpp
+++ b/tests/Main.cpp
@@ -448,10 +448,10 @@ void BezierDerivativeCurveConstraintTest(bool& error)
 
     std::string errMsg1("In test BezierDerivativeCurveConstraintTest, Error While checking checking degree of bezier curve :");
     std::string errMsg2("In test BezierDerivativeCurveConstraintTest, Error While checking checking size of bezier curve :");
-    if (cf.degree_ != params.size() + 3)
+    if (cf.order_ != params.size() + 3)
     {
         error = true;
-        std::cout << errMsg1 << cf.degree_ << " ; " << params.size()+3 << std::endl;
+        std::cout << errMsg1 << cf.order_ << " ; " << params.size()+3 << std::endl;
     }
     if (cf.size_   != params.size() + 4)
     {
@@ -1010,7 +1010,7 @@ void BezierSplitCurve(bool& error)
         std::pair<bezier_curve_t,bezier_curve_t> cs = c.split(ts);
 
         // test on splitted curves :
-        if(! ((c.degree_ == cs.first.degree_) && (c.degree_ == cs.second.degree_) ))
+        if(! ((c.order_ == cs.first.order_) && (c.order_ == cs.second.order_) ))
         {
             error = true;
             std::cout<<"BezierSplitCurve, ERROR Degree of the splitted curve are not the same as the original curve"<<std::endl;
@@ -1305,7 +1305,13 @@ void piecewiseCurveTest(bool& error)
     }
 
     // CONVERT PIECEWISE POLYNOMIAL CURVES TO BEZIER AND HERMITE
-
+    std::string errmsg5("in piecewise polynomial curve test, Error while checking piecewise curve conversion");
+    piecewise_bezier_curve_t pc_bezier = pc.convert_piecewise_curve_to_bezier<bezier_curve_t>();
+    CompareCurves<piecewise_polynomial_curve_t, piecewise_bezier_curve_t>(pc, pc_bezier, errmsg5, error);
+    piecewise_cubic_hermite_curve_t pc_hermite = pc.convert_piecewise_curve_to_cubic_hermite<cubic_hermite_spline_t>();
+    CompareCurves<piecewise_polynomial_curve_t, piecewise_cubic_hermite_curve_t>(pc, pc_hermite, errmsg5, error);
+    piecewise_polynomial_curve_t pc_polynomial_same = pc.convert_piecewise_curve_to_polynomial<polynomial_t>();
+    CompareCurves<piecewise_polynomial_curve_t, piecewise_polynomial_curve_t>(pc, pc_polynomial_same, errmsg5, error);
 }
 
 void curveAbcDimDynamicTest(bool& error)
-- 
GitLab