diff --git a/include/opendrive/opendrive_geometry.h b/include/opendrive/opendrive_geometry.h
index 6989dfc708da38fd7e3705405e498702cc4f3321..50baf13b881b196650c291b0368da3ea77752a6c 100644
--- a/include/opendrive/opendrive_geometry.h
+++ b/include/opendrive/opendrive_geometry.h
@@ -27,7 +27,7 @@ class COpendriveGeometry
     virtual void save_params(planView::geometry_type &geometry_info) = 0;
     virtual std::string get_name(void)=0;
     void set_start_pose(TOpendriveWorldPose &pose);
-    virtual void set_max_s(double s);
+    void set_max_s(double s);
     void set_min_s(double s);
   public:
     COpendriveGeometry(TOpendriveWorldPose &start_pose,double length);
diff --git a/include/opendrive/opendrive_param_poly3.h b/include/opendrive/opendrive_param_poly3.h
index 462dbb0aef9009cb3edd659e56b0cb7eb8a244b7..53fa3aa0525de9bf5ebaadc81d620991c360c703 100644
--- a/include/opendrive/opendrive_param_poly3.h
+++ b/include/opendrive/opendrive_param_poly3.h
@@ -27,10 +27,9 @@ class COpendriveParamPoly3 : public COpendriveGeometry
     virtual void load_params(const planView::geometry_type &geometry_info);
     virtual void save_params(planView::geometry_type &geometry_info);
     virtual std::string get_name(void);
-    void set_start_pose(TOpendriveWorldPose &pose,double s);
-    virtual void set_max_s(double s);
   public:
     COpendriveParamPoly3(TOpendriveWorldPose &start_pose,TOpendrivePoly3Params &u_params,TOpendrivePoly3Params &v_params);
+    COpendriveParamPoly3(TOpendriveWorldPose &start_pose,TOpendriveWorldPose &end_pose);
     virtual COpendriveGeometry *clone(void);
     virtual void get_curvature(double &start,double &end);
     virtual void get_curvature_at(double length,double &curvature);
diff --git a/src/opendrive/opendrive_param_poly3.cpp b/src/opendrive/opendrive_param_poly3.cpp
index 9f570bce2c5f7f7f625fc6bd01dc759f51dc167b..bbb3354bb1a7423782396212724aaaf09ec430a7 100644
--- a/src/opendrive/opendrive_param_poly3.cpp
+++ b/src/opendrive/opendrive_param_poly3.cpp
@@ -30,51 +30,19 @@ COpendriveParamPoly3::COpendriveParamPoly3(const COpendriveParamPoly3 &object) :
   this->normalized=object.normalized;
 }
 
-bool COpendriveParamPoly3::transform_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
-{
-  double p = (this->normalized ? track.s/(this->max_s - this->min_s):track.s);
-  double p2 = p*p;
-  double p3 = p2*p;
-  double du = this->u.b + 2*this->u.c*p + 3*this->u.d*p2;
-  double dv = this->v.b + 2*this->v.c*p + 3*this->v.d*p2;
-  double alpha;
-  if(p==0.0)
-    alpha = 0.0;
-  else
-    alpha = std::atan2(dv,du);
-  local.u = this->u.a + this->u.b*p + this->u.c*p2 + this->u.d*p3 - track.t*std::sin(alpha);
-  local.v = this->v.a + this->v.b*p + this->v.c*p2 + this->v.d*p3 + track.t*std::cos(alpha);
-  local.heading = normalize_angle(track.heading + alpha);
-
-  return true;
-}
-
-void COpendriveParamPoly3::print(std::ostream &out)
-{
-  COpendriveGeometry::print(out);
-  std::cout << "          U params: a = " << this->u.a << ", b = " << this->u.b  << ", c = " << this->u.c  << ", d = " << this->u.d << std::endl;
-  std::cout << "          V params: a = " << this->v.a << ", b = " << this->v.b  << ", c = " << this->v.c  << ", d = " << this->v.d << std::endl;
-  if(this->normalized)
-    std::cout << "          Normalized" << std::endl;
-  else
-    std::cout << "          Not normalized" << std::endl;
-}
-
-std::string COpendriveParamPoly3::get_name(void)
-{
-  return std::string("Parametric polynomial 3th degree");
-}
-
-void COpendriveParamPoly3::set_start_pose(TOpendriveWorldPose &pose,double s)
+COpendriveParamPoly3::COpendriveParamPoly3(TOpendriveWorldPose &start_pose,TOpendriveWorldPose &end_pose)
 {
+  TOpendriveWorldPose end_pose_zero,end_pose_rot;
   Eigen::MatrixXd A=Eigen::MatrixXd::Zero(6,8),pinv;
-  Eigen::VectorXd b=Eigen::VectorXd::Zero(6,1),sol; 
-  TOpendriveWorldPose end_pose,new_end_pose;
+  Eigen::VectorXd b=Eigen::VectorXd::Zero(6,1),sol;
+  double length=0.0,x,prev_x,y,prev_y,p,p2,p3;
 
-  end_pose=this->get_end_pose();
-  new_end_pose.heading=end_pose.heading-pose.heading;
-  new_end_pose.x=(end_pose.x-pose.x)*std::cos(pose.heading)+(end_pose.y-pose.y)*std::sin(pose.heading);
-  new_end_pose.y=-(end_pose.x-pose.x)*std::sin(pose.heading)+(end_pose.y-pose.y)*std::cos(pose.heading);
+  end_pose_zero.x=end_pose.x-start_pose.x;
+  end_pose_zero.y=end_pose.y-start_pose.y;
+  end_pose_zero.heading=end_pose.heading;
+  end_pose_rot.x=end_pose_zero.x*std::cos(start_pose.heading)+end_pose_zero.y*std::sin(start_pose.heading);
+  end_pose_rot.y=-end_pose_zero.x*std::sin(start_pose.heading)+end_pose_zero.y*std::cos(start_pose.heading);
+  end_pose_rot.heading=end_pose.heading-start_pose.heading;
   A(0,0)=1.0;
   A(1,4)=1.0;
   A(2,0)=1.0;
@@ -87,19 +55,18 @@ void COpendriveParamPoly3::set_start_pose(TOpendriveWorldPose &pose,double s)
   A(3,7)=1.0;
   A(4,1)=-tan(0.0);
   A(4,5)=1.0;
-  A(5,1)=-tan(new_end_pose.heading);
-  A(5,2)=-2.0*tan(new_end_pose.heading);
-  A(5,3)=-3.0*tan(new_end_pose.heading);
+  A(5,1)=-tan(end_pose_rot.heading);
+  A(5,2)=-2.0*tan(end_pose_rot.heading);
+  A(5,3)=-3.0*tan(end_pose_rot.heading);
   A(5,5)=1.0;
   A(5,6)=2.0;
   A(5,7)=3.0;
   pinv=A.completeOrthogonalDecomposition().pseudoInverse();
   b(0)=0.0;
   b(1)=0.0;
-  b(2)=new_end_pose.x;
-  b(3)=new_end_pose.y;
+  b(2)=end_pose_rot.x;
+  b(3)=end_pose_rot.y;
   sol=pinv*b;
-  
   this->u.a=sol(0);
   this->u.b=sol(1);
   this->u.c=sol(2);
@@ -109,57 +76,59 @@ void COpendriveParamPoly3::set_start_pose(TOpendriveWorldPose &pose,double s)
   this->v.c=sol(6);
   this->v.d=sol(7);
 
-  COpendriveGeometry::set_start_pose(pose);
-  COpendriveGeometry::set_max_s(s);
+  this->normalized=true;
+  // compute start pose
+  COpendriveGeometry::set_start_pose(start_pose);
+  // compute length
+  prev_x=this->u.a;
+  prev_y=this->v.a;
+  for(unsigned int i=1;i<=100;i++)
+  {
+    p=i*0.01;
+    p2=p*p;
+    p3=p2*p;
+    x=this->u.a + this->u.b*p + this->u.c*p2 + this->u.d*p3;
+    y=this->v.a + this->v.b*p + this->v.c*p2 + this->v.d*p3;
+    length+=sqrt(pow(x-prev_x,2.0)+pow(y-prev_y,2.0));
+    prev_x=x;
+    prev_y=y;
+  }
+  this->set_max_s(length);
 }
 
-void COpendriveParamPoly3::set_max_s(double s)
+bool COpendriveParamPoly3::transform_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
 {
-  Eigen::MatrixXd A=Eigen::MatrixXd::Zero(6,8),pinv;
-  Eigen::VectorXd b=Eigen::VectorXd::Zero(6,1),sol;
-  TOpendriveWorldPose end_pose,new_end_pose;
+  double p = (this->normalized ? track.s/(this->max_s - this->min_s):track.s);
+  double p2 = p*p;
+  double p3 = p2*p;
+  double du = this->u.b + 2*this->u.c*p + 3*this->u.d*p2;
+  double dv = this->v.b + 2*this->v.c*p + 3*this->v.d*p2;
+  double alpha;
+  if(p==0.0)
+    alpha = 0.0;
+  else
+    alpha = std::atan2(dv,du);
+  local.u = this->u.a + this->u.b*p + this->u.c*p2 + this->u.d*p3 - track.t*std::sin(alpha);
+  local.v = this->v.a + this->v.b*p + this->v.c*p2 + this->v.d*p3 + track.t*std::cos(alpha);
+  local.heading = normalize_angle(track.heading + alpha);
 
-  if(this->get_pose_at(s,end_pose))
-  {
-    new_end_pose.heading=end_pose.heading-this->pose.heading;
-    new_end_pose.x=(end_pose.x-this->pose.x)*std::cos(this->pose.heading)+(end_pose.y-this->pose.y)*std::sin(this->pose.heading);
-    new_end_pose.y=-(end_pose.x-this->pose.x)*std::sin(this->pose.heading)+(end_pose.y-this->pose.y)*std::cos(this->pose.heading);
-    A(0,0)=1.0;
-    A(1,4)=1.0;
-    A(2,0)=1.0;
-    A(2,1)=1.0;
-    A(2,2)=1.0;
-    A(2,3)=1.0;
-    A(3,4)=1.0;
-    A(3,5)=1.0;
-    A(3,6)=1.0;
-    A(3,7)=1.0;
-    A(4,1)=-tan(0.0);
-    A(4,5)=1.0;
-    A(5,1)=-tan(new_end_pose.heading);
-    A(5,2)=-2.0*tan(new_end_pose.heading);
-    A(5,3)=-3.0*tan(new_end_pose.heading);
-    A(5,5)=1.0;
-    A(5,6)=2.0;
-    A(5,7)=3.0;
-    pinv=A.completeOrthogonalDecomposition().pseudoInverse();
-    b(0)=0.0;
-    b(1)=0.0;
-    b(2)=new_end_pose.x;
-    b(3)=new_end_pose.y;
-    sol=pinv*b;
+  return true;
+}
 
-    this->u.a=sol(0);
-    this->u.b=sol(1);
-    this->u.c=sol(2);
-    this->u.d=sol(3);
-    this->v.a=sol(4);
-    this->v.b=sol(5);
-    this->v.c=sol(6);
-    this->v.d=sol(7);
-  }
+void COpendriveParamPoly3::print(std::ostream &out)
+{
+  COpendriveGeometry::print(out);
+  std::cout << "          U params: a = " << this->u.a << ", b = " << this->u.b  << ", c = " << this->u.c  << ", d = " << this->u.d << std::endl;
+  std::cout << "          V params: a = " << this->v.a << ", b = " << this->v.b  << ", c = " << this->v.c  << ", d = " << this->v.d << std::endl;
+  if(this->normalized)
+    std::cout << "          Normalized" << std::endl;
+  else
+    std::cout << "          Not normalized" << std::endl;
+}
 
-  COpendriveGeometry::set_max_s(s);
+std::string COpendriveParamPoly3::get_name(void)
+{
+  return std::string("Parametric polynomial 3th degree");
 }
 
 void COpendriveParamPoly3::load_params(const planView::geometry_type &geometry_info)