From b1fc7a4b1e4de56eb8b080475eaa5f54c6ddada5 Mon Sep 17 00:00:00 2001
From: Sergi Hernandez Juan <shernand@iri.upc.edu>
Date: Wed, 13 Jan 2021 17:09:20 +0100
Subject: [PATCH] Moved the opendrive geometry from the lane to the segment. It
 describes the center lane. The links keep the splines to generate the
 trajectory. Solved a bug with the computation of the curvature for lanes
 other than the central one.

---
 include/opendrive_arc.h          |   3 +-
 include/opendrive_geometry.h     |   8 +-
 include/opendrive_lane.h         |   5 +-
 include/opendrive_line.h         |   3 +-
 include/opendrive_link.h         |   4 +-
 include/opendrive_param_poly3.h  |   3 +-
 include/opendrive_road_node.h    |   9 +-
 include/opendrive_road_segment.h |  13 +-
 include/opendrive_spiral.h       |   3 +-
 src/opendrive_arc.cpp            |   2 +-
 src/opendrive_geometry.cpp       |  17 +-
 src/opendrive_lane.cpp           | 166 ++++---------------
 src/opendrive_line.cpp           |   2 +-
 src/opendrive_link.cpp           |  39 ++++-
 src/opendrive_param_poly3.cpp    |   2 +-
 src/opendrive_road.cpp           |  23 ++-
 src/opendrive_road_node.cpp      | 216 ++++++------------------
 src/opendrive_road_segment.cpp   | 275 ++++++++++++++++++++++++-------
 src/opendrive_spiral.cpp         |   2 +-
 19 files changed, 410 insertions(+), 385 deletions(-)

diff --git a/include/opendrive_arc.h b/include/opendrive_arc.h
index e5bc79f..683b321 100644
--- a/include/opendrive_arc.h
+++ b/include/opendrive_arc.h
@@ -6,12 +6,13 @@
 class COpendriveArc : public COpendriveGeometry
 {
   friend class COpendriveRoadNode;
+  friend class COpendriveRoadSegment;
   private:
     double curvature;
   protected:
     COpendriveArc();
     COpendriveArc(const COpendriveArc &object);
-    virtual bool transform_local_pose(TOpendriveTrackPose &track,TOpendriveLocalPose &local) const;
+    virtual bool transform_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const;
     virtual void print(std::ostream &out);
     virtual void load_params(const planView::geometry_type &geometry_info);
     virtual std::string get_name(void);
diff --git a/include/opendrive_geometry.h b/include/opendrive_geometry.h
index d54840d..f9c7285 100644
--- a/include/opendrive_geometry.h
+++ b/include/opendrive_geometry.h
@@ -11,6 +11,7 @@
 class COpendriveGeometry
 {
   friend class COpendriveRoadNode;
+  friend class COpendriveRoadSegment;
   private:
   protected:
     COpendriveGeometry();
@@ -20,7 +21,7 @@ class COpendriveGeometry
     double min_s; ///< Starting track coordenate "s" for the geometry.
     double max_s; ///< Ending track coordenate "s" for the geometry.
     TOpendriveWorldPose pose;
-    virtual bool transform_local_pose(TOpendriveTrackPose &track,TOpendriveLocalPose &local) const = 0;
+    virtual bool transform_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const = 0;
     virtual void print(std::ostream &out);
     virtual void load_params(const planView::geometry_type &geometry_info) = 0;
     virtual std::string get_name(void)=0;
@@ -30,14 +31,15 @@ class COpendriveGeometry
     void set_min_s(double s);
   public:
     virtual COpendriveGeometry *clone(void) = 0;
-    bool get_local_pose(TOpendriveTrackPose &track,TOpendriveLocalPose &local) const;
-    bool get_world_pose(TOpendriveTrackPose &track,TOpendriveWorldPose &world) const;
+    bool get_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const;
+    bool get_world_pose(const TOpendriveTrackPose &track,TOpendriveWorldPose &world) const;
     bool in_range(double s) const;
     double get_length(void) const;
     virtual void get_curvature(double &start,double &end)=0;
     double get_max_s(void) const;
     double get_min_s(void) const;
     TOpendriveWorldPose get_start_pose(void) const;
+    TOpendriveWorldPose get_end_pose(void) const;
     void operator=(const COpendriveGeometry &object);
     friend std::ostream& operator<<(std::ostream& out, COpendriveGeometry &geom);
     virtual ~COpendriveGeometry();
diff --git a/include/opendrive_lane.h b/include/opendrive_lane.h
index 6b91343..4208f4c 100644
--- a/include/opendrive_lane.h
+++ b/include/opendrive_lane.h
@@ -71,13 +71,14 @@ class COpendriveLane
     double get_width(void) const;
     double get_speed(void) const;
     double get_offset(void) const;
+    double get_center_offset(void) const;
     unsigned int get_index(void) const;
     int get_id(void) const;
     TOpendriveWorldPose get_start_pose(void) const;
     TOpendriveWorldPose get_end_pose(void) const;
     double get_length(void) const;
-    TOpendriveLocalPose transform_to_local_pose(TOpendriveTrackPose &track);
-    TOpendriveWorldPose transform_to_world_pose(TOpendriveTrackPose &track);
+    TOpendriveLocalPose transform_to_local_pose(TOpendriveTrackPose &track) const;
+    TOpendriveWorldPose transform_to_world_pose(TOpendriveTrackPose &track) const;
     unsigned int get_closest_node_index(TOpendriveWorldPose &pose,double angle_tol=0.1);
     friend std::ostream& operator<<(std::ostream& out, COpendriveLane &lane);
     ~COpendriveLane();
diff --git a/include/opendrive_line.h b/include/opendrive_line.h
index 3116aa9..b544bce 100644
--- a/include/opendrive_line.h
+++ b/include/opendrive_line.h
@@ -6,11 +6,12 @@
 class COpendriveLine : public COpendriveGeometry
 {
   friend class COpendriveRoadNode;
+  friend class COpendriveRoadSegment;
   private:
   protected:
     COpendriveLine();
     COpendriveLine(const COpendriveGeometry &object);
-    virtual bool transform_local_pose(TOpendriveTrackPose &track,TOpendriveLocalPose &local) const;
+    virtual bool transform_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const;
     virtual void print(std::ostream &out);
     virtual void load_params(const planView::geometry_type &geometry_info);
     virtual std::string get_name(void);
diff --git a/include/opendrive_link.h b/include/opendrive_link.h
index ae6701b..96a2789 100644
--- a/include/opendrive_link.h
+++ b/include/opendrive_link.h
@@ -36,8 +36,8 @@ class COpendriveLink
     void generate(double start_curvature,double end_curvature,double length,bool lane);
     void update_references(segment_up_ref_t &segment_refs,lane_up_ref_t &lanei_refs,node_up_ref_t &node_refs);
     bool clean_references(node_up_ref_t &refs);
-    void update_start_pose(TOpendriveWorldPose *start=NULL);
-    void update_end_pose(TOpendriveWorldPose *end=NULL);
+    TPoint update_start_pose(TOpendriveWorldPose *start=NULL);
+    TPoint update_end_pose(TOpendriveWorldPose *end=NULL);
   public:
     const COpendriveRoadNode &get_prev(void) const;
     const COpendriveRoadNode &get_next(void) const;
diff --git a/include/opendrive_param_poly3.h b/include/opendrive_param_poly3.h
index 2b03eb1..c40fdae 100644
--- a/include/opendrive_param_poly3.h
+++ b/include/opendrive_param_poly3.h
@@ -14,6 +14,7 @@ typedef struct
 class COpendriveParamPoly3 : public COpendriveGeometry
 {
   friend class COpendriveRoadNode;
+  friend class COpendriveRoadSegment;
   private:
     TOpendrivePoly3Params u;
     TOpendrivePoly3Params v;
@@ -21,7 +22,7 @@ class COpendriveParamPoly3 : public COpendriveGeometry
   protected:
     COpendriveParamPoly3();
     COpendriveParamPoly3(const COpendriveParamPoly3 &object);
-    virtual bool transform_local_pose(TOpendriveTrackPose &track,TOpendriveLocalPose &local) const;
+    virtual bool transform_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const;
     virtual void print(std::ostream &out);
     virtual void load_params(const planView::geometry_type &geometry_info);
     virtual std::string get_name(void);
diff --git a/include/opendrive_road_node.h b/include/opendrive_road_node.h
index 9951642..49fa7a6 100644
--- a/include/opendrive_road_node.h
+++ b/include/opendrive_road_node.h
@@ -10,8 +10,10 @@
 typedef struct
 {
   COpendriveLane * lane;
-  COpendriveGeometry *geometry;
   COpendriveRoadSegment *segment;
+  double start_curvature;
+  double end_curvature;
+  double length;
 }TOpendriveRoadNodeParent;
 
 class COpendriveRoadNode
@@ -31,7 +33,6 @@ class COpendriveRoadNode
     COpendriveRoadNode();
     COpendriveRoadNode(const COpendriveRoadNode &object);
     void free(void);
-    void load(const planView::geometry_type &geom_info,COpendriveLane *lane,COpendriveRoadSegment *segment);
     bool add_link(COpendriveRoadNode *node,opendrive_mark_t mark,COpendriveRoadSegment *segment,COpendriveLane *lane);
     void add_link(COpendriveLink *link);
     void remove_link(COpendriveLink *link);
@@ -42,8 +43,7 @@ class COpendriveRoadNode
     void set_scale_factor(double scale);
     void set_index(unsigned int index);
     void set_pose(TOpendriveWorldPose &start);
-    void add_parent(const planView::geometry_type &geom_info,COpendriveLane *lane,COpendriveRoadSegment *segment);
-    void add_parent(COpendriveGeometry *geometry,COpendriveLane *lane,COpendriveRoadSegment *segment);
+    void add_parent(COpendriveLane *lane,COpendriveRoadSegment *segment,double length,double start_curvature,double end_curvature);
     TOpendriveRoadNodeParent *get_parent_with_lane(const COpendriveLane *lane);
     TOpendriveRoadNodeParent *get_parent_with_segment(const COpendriveRoadSegment *segment);
     bool updated(node_up_ref_t &refs);
@@ -59,7 +59,6 @@ class COpendriveRoadNode
     unsigned int get_num_parents(void) const;
     const COpendriveRoadSegment& get_parent_segment(unsigned int index) const;
     const COpendriveLane &get_parent_lane(unsigned int index) const;
-    const COpendriveGeometry &get_geometry(unsigned int index) const;
     TOpendriveWorldPose get_pose(void) const;
     unsigned int get_num_links(void) const;
     const COpendriveLink &get_link(unsigned int index) const;
diff --git a/include/opendrive_road_segment.h b/include/opendrive_road_segment.h
index d00bb7f..37dd02c 100644
--- a/include/opendrive_road_segment.h
+++ b/include/opendrive_road_segment.h
@@ -11,6 +11,12 @@
 #include "opendrive_object.h"
 #include "opendrive_road.h"
 #include "opendrive_road_node.h"
+#include "opendrive_geometry.h"
+
+typedef struct{
+  COpendriveGeometry *opendrive;
+  CG2Spline *spline;
+}TOpendriveRoadSegmentGeometry;
 
 class COpendriveRoadSegment
 {
@@ -20,6 +26,7 @@ class COpendriveRoadSegment
   private:
     std::map<int,COpendriveLane *> lanes;
     std::vector<COpendriveRoadNode *> nodes;
+    std::vector<TOpendriveRoadSegmentGeometry> geometries;
     COpendriveRoad *parent_road;
     double resolution;
     double scale_factor;
@@ -51,8 +58,9 @@ class COpendriveRoadSegment
     void add_lanes(lanes::laneSection_type &lane_section);
     void add_lane(const ::lane &lane_info);
     void remove_lane(COpendriveLane *lane);
-    void add_nodes(OpenDRIVE::road_type &road_info);
-    void add_node(const planView::geometry_type &geom_info,COpendriveLane *lane);
+    void add_geometries(OpenDRIVE::road_type &road_info);
+    void add_nodes(void);
+    void add_node(TOpendriveRoadSegmentGeometry &geometry,COpendriveLane *lane);
     void add_empty_node(TOpendriveWorldPose &pose,COpendriveLane *lane);
     void remove_node(COpendriveRoadNode *node);
     bool has_node(COpendriveRoadNode *node);
@@ -80,6 +88,7 @@ class COpendriveRoadSegment
     const COpendriveObject &get_object(unsigned int index) const;
     unsigned int get_num_connecting(void) const;
     const COpendriveRoadSegment &get_connecting(unsigned int index) const;
+    double get_length(void);
     TOpendriveLocalPose transform_to_local_pose(const TOpendriveTrackPose &track);
     TOpendriveWorldPose transform_to_world_pose(const TOpendriveTrackPose &track);
     friend std::ostream& operator<<(std::ostream& out, COpendriveRoadSegment &segment);
diff --git a/include/opendrive_spiral.h b/include/opendrive_spiral.h
index 12b0a36..106597e 100644
--- a/include/opendrive_spiral.h
+++ b/include/opendrive_spiral.h
@@ -6,13 +6,14 @@
 class COpendriveSpiral : public COpendriveGeometry
 {
   friend class COpendriveRoadNode;
+  friend class COpendriveRoadSegment;
   private:
     double start_curvature;
     double end_curvature;
   protected:
     COpendriveSpiral();
     COpendriveSpiral(const COpendriveSpiral &object);
-    virtual bool transform_local_pose(TOpendriveTrackPose &track,TOpendriveLocalPose &local) const;
+    virtual bool transform_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const;
     virtual void print(std::ostream &out);
     virtual void load_params(const planView::geometry_type &geometry_info);
     virtual std::string get_name(void);
diff --git a/src/opendrive_arc.cpp b/src/opendrive_arc.cpp
index b8567a0..4d18947 100644
--- a/src/opendrive_arc.cpp
+++ b/src/opendrive_arc.cpp
@@ -11,7 +11,7 @@ COpendriveArc::COpendriveArc(const COpendriveArc &object) : COpendriveGeometry(o
   this->curvature=object.curvature;
 }
 
-bool COpendriveArc::transform_local_pose(TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
+bool COpendriveArc::transform_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
 {
   double alpha;
 
diff --git a/src/opendrive_geometry.cpp b/src/opendrive_geometry.cpp
index 82d9cd2..dc3ef7b 100644
--- a/src/opendrive_geometry.cpp
+++ b/src/opendrive_geometry.cpp
@@ -62,12 +62,12 @@ void COpendriveGeometry::set_min_s(double s)
   this->min_s=s*this->scale_factor;
 }
 
-bool COpendriveGeometry::get_local_pose(TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
+bool COpendriveGeometry::get_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
 {
   return this->transform_local_pose(track,local);
 }
 
-bool COpendriveGeometry::get_world_pose(TOpendriveTrackPose &track,TOpendriveWorldPose &world) const
+bool COpendriveGeometry::get_world_pose(const TOpendriveTrackPose &track,TOpendriveWorldPose &world) const
 {
   TOpendriveLocalPose local;
 
@@ -116,6 +116,19 @@ TOpendriveWorldPose COpendriveGeometry::get_start_pose(void) const
   return tmp_pose;
 }
 
+TOpendriveWorldPose COpendriveGeometry::get_end_pose(void) const
+{
+  TOpendriveTrackPose track_pose;
+  TOpendriveWorldPose world_pose;
+ 
+  track_pose.s=this->get_length();
+  track_pose.t=0.0;
+  track_pose.heading=0.0;
+  this->get_world_pose(track_pose,world_pose);
+
+  return world_pose;
+}
+
 void COpendriveGeometry::operator=(const COpendriveGeometry &object)
 {
   this->min_s = object.min_s;
diff --git a/src/opendrive_lane.cpp b/src/opendrive_lane.cpp
index 53dbe87..57f9d9e 100644
--- a/src/opendrive_lane.cpp
+++ b/src/opendrive_lane.cpp
@@ -628,6 +628,14 @@ double COpendriveLane::get_offset(void) const
   return this->offset/this->scale_factor;
 }
 
+double COpendriveLane::get_center_offset(void) const
+{
+  if(this->id<0)
+    return (this->offset-this->width/2.0)/this->scale_factor;
+  else
+    return (this->offset+this->width/2.0)/this->scale_factor;
+}
+
 unsigned int COpendriveLane::get_index(void) const
 {
   return this->index;
@@ -642,40 +650,20 @@ TOpendriveWorldPose COpendriveLane::get_start_pose(void) const
 {
   TOpendriveTrackPose track_pose;
   TOpendriveWorldPose world_pose;
-  TOpendriveRoadNodeParent *parent;
   std::stringstream error;
 
-  track_pose.heading=0.0;
+  track_pose.t=0.0;
   if(this->id<0)// right lane
   {
-    track_pose.t=this->get_offset()-this->get_width()/2.0;
     track_pose.s=0.0;
-    parent=this->nodes[0]->get_parent_with_lane(this);
-    if(parent!=NULL)
-      parent->geometry->get_world_pose(track_pose,world_pose);
-    else
-    {
-      error << "Node " << this->nodes[0]->get_index() << " does not have lane " << this->id << " of segment " << this->segment->get_name() << " as a parent";
-      throw CException(_HERE_,error.str());
-    }
+    track_pose.heading=0.0;
   }
   else
   {
-    track_pose.t=this->get_offset()+this->get_width()/2.0;
-    parent=this->nodes[0]->get_parent_with_lane(this);
-    if(parent!=NULL)
-    {
-      track_pose.s=parent->geometry->get_length();
-      parent->geometry->get_world_pose(track_pose,world_pose);
-    }
-    else
-    {
-      error << "Node " << this->nodes[0]->get_index() << " does not have lane " << this->id << " of segment " << this->segment->get_name() << " as a parent";
-      throw CException(_HERE_,error.str());
-    }
+    track_pose.s=this->segment->get_length();
+    track_pose.heading=3.14159;
   }
-  if(this->id>0)
-    world_pose.heading=normalize_angle(world_pose.heading+3.14159);
+  world_pose=this->transform_to_world_pose(track_pose);
 
   return world_pose;
 }
@@ -684,141 +672,57 @@ TOpendriveWorldPose COpendriveLane::get_end_pose(void) const
 {
   TOpendriveTrackPose track_pose;
   TOpendriveWorldPose world_pose;
-  TOpendriveRoadNodeParent *parent;
   std::stringstream error;
   
-  track_pose.heading=0.0;
-  if(this->id>0)// left lane
-  { 
-    track_pose.t=this->get_offset()+this->get_width()/2.0;
-    track_pose.s=0.0;
-    parent=this->nodes[this->nodes.size()-1]->get_parent_with_lane(this);
-    if(parent!=NULL)
-      parent->geometry->get_world_pose(track_pose,world_pose);
-    else
-    {
-      error << "Node " << this->nodes[this->nodes.size()-1]->get_index() << " does not have lane " << this->id << " of segment " << this->segment->get_name() << " as a parent";
-      throw CException(_HERE_,error.str());
-    }
+  track_pose.t=0.0;
+  if(this->id<0)// right_lane
+  {
+    track_pose.s=this->segment->get_length();
+    track_pose.heading=0.0;
   }
   else
-  { 
-    track_pose.t=this->get_offset()-this->get_width()/2.0;
-    parent=this->nodes[this->nodes.size()-1]->get_parent_with_lane(this);
-    if(parent!=NULL)
-    {
-      track_pose.s=parent->geometry->get_length();
-      parent->geometry->get_world_pose(track_pose,world_pose);
-    }
-    else
-    {
-      error << "Node " << this->nodes[this->nodes.size()-1]->get_index() << " does not have lane " << this->id << " of segment " << this->segment->get_name() << " as a parent";
-      throw CException(_HERE_,error.str());
-    }
+  {
+    track_pose.s=0.0;
+    track_pose.heading=3.14159;
   }
-  if(this->id>0)
-    world_pose.heading=normalize_angle(world_pose.heading+3.14159);
+  world_pose=this->transform_to_world_pose(track_pose);
 
   return world_pose;
 }
 
 double COpendriveLane::get_length(void) const
 {
-  TOpendriveRoadNodeParent *parent;
   std::stringstream error;
   double length=0.0;
 
   for(unsigned int i=0;i<this->nodes.size();i++)
   {
-    parent=this->nodes[i]->get_parent_with_lane(this);
-    if(parent!=NULL)
-      length+=parent->geometry->get_length();
-    else
+    for(unsigned int j=0;j<this->nodes[i]->get_num_links();j++)
     {
-      error << "Node " << this->nodes[i]->get_index() << " does not have lane " << this->id << " of segment " << this->segment->get_name() << " as a parent";
-      throw CException(_HERE_,error.str());
+      if(&this->nodes[i]->get_link(j).get_parent_lane()==this)
+        length+=this->nodes[i]->links[j]->get_length();
     }
   }
 
   return length;
 }
 
-TOpendriveLocalPose COpendriveLane::transform_to_local_pose(TOpendriveTrackPose &track)
+TOpendriveLocalPose COpendriveLane::transform_to_local_pose(TOpendriveTrackPose &track) const
 {
-  TOpendriveLocalPose local;
-  TOpendriveRoadNodeParent *parent;
-  std::stringstream error;
+  TOpendriveTrackPose pose;
 
-  if(track.s<0.0)
-  {
-    error << "Invalid track pose (s=" << track.s << ",t=" << track.t << ",heading=" << track.heading << ")";
-    throw CException(_HERE_,error.str());
-  }
-  for(unsigned int i=0;i<this->nodes.size();i++)
-  { 
-    parent=this->nodes[i]->get_parent_with_lane(this);
-    if(parent!=NULL)
-    {
-      if(track.s<=parent->geometry->get_length())
-      { 
-        if(!parent->geometry->get_local_pose(track,local))
-        {
-          error << "Impossible to transform to local coordinates pose (s=" << track.s << ",t=" << track.t << ",heading=" << track.heading << ") in lane " << parent->lane->get_id() << " of segment " << parent->segment->get_name();
-          throw CException(_HERE_,error.str());
-        }
-        return local;
-      }
-      else
-        track.s-=parent->geometry->get_length();
-    }
-    else
-    {
-      error << "Node " << this->nodes[i]->get_index() << " does not have lane " << this->id << " of segment " << this->segment->get_name() << " as a parent";
-      throw CException(_HERE_,error.str());
-    }
-  }
-
-  error << "Track pose (s=" << track.s << ",t=" << track.t << ",heading=" << track.heading << ") does not belong to lane  " << this->id << " of segment " << this->segment->get_name();
-  throw CException(_HERE_,error.str());
+  pose=track;
+  pose.t+=this->get_center_offset();
+  return this->segment->transform_to_local_pose(pose);
 }
 
-TOpendriveWorldPose COpendriveLane::transform_to_world_pose(TOpendriveTrackPose &track)
+TOpendriveWorldPose COpendriveLane::transform_to_world_pose(TOpendriveTrackPose &track) const
 { 
-  TOpendriveWorldPose world;
-  TOpendriveRoadNodeParent *parent;
-  std::stringstream error;
-
-  if(track.s<0.0)
-  {
-    error << "Invalid track pose (s=" << track.s << ",t=" << track.t << ",heading=" << track.heading << ")";
-    throw CException(_HERE_,error.str());
-  }
-  for(unsigned int i=0;i<this->nodes.size();i++)
-  {
-    parent=this->nodes[i]->get_parent_with_lane(this);
-    if(parent!=NULL)
-    {
-      if(track.s<=parent->geometry->get_length())
-      {
-        if(!parent->geometry->get_world_pose(track,world))
-        {
-          error << "Impossible to transform to local coordinates pose (s=" << track.s << ",t=" << track.t << ",heading=" << track.heading << ") in lane " << parent->lane->get_id() << " of segment " << parent->segment->get_name();
-          throw CException(_HERE_,error.str());
-        }
-        return world;
-      }
-      else
-        track.s-=parent->geometry->get_length();
-    }
-    else
-    {
-      error << "Node " << this->nodes[i]->get_index() << " does not have lane " << this->id << " of segment " << this->segment->get_name() << " as a parent";
-      throw CException(_HERE_,error.str());
-    }
-  }
+  TOpendriveTrackPose pose;
 
-  error << "Track pose (s=" << track.s << ",t=" << track.t << ",heading=" << track.heading << ") does not belong to lane  " << this->id << " of segment " << this->segment->get_name();
-  throw CException(_HERE_,error.str());
+  pose=track;
+  pose.t+=this->get_center_offset();
+  return this->segment->transform_to_world_pose(pose);
 }
 
 unsigned int COpendriveLane::get_closest_node_index(TOpendriveWorldPose &pose,double angle_tol)
diff --git a/src/opendrive_line.cpp b/src/opendrive_line.cpp
index 3f82f4d..9b0fa5e 100644
--- a/src/opendrive_line.cpp
+++ b/src/opendrive_line.cpp
@@ -10,7 +10,7 @@ COpendriveLine::COpendriveLine(const COpendriveGeometry &object) : COpendriveGeo
 
 }
 
-bool COpendriveLine::transform_local_pose(TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
+bool COpendriveLine::transform_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
 {
   local.u=track.s;
   local.v=track.t;
diff --git a/src/opendrive_link.cpp b/src/opendrive_link.cpp
index 5aff42f..ddffa45 100644
--- a/src/opendrive_link.cpp
+++ b/src/opendrive_link.cpp
@@ -53,11 +53,34 @@ void COpendriveLink::set_parent_lane(COpendriveLane *lane)
 void COpendriveLink::set_resolution(double res)
 {
   this->resolution=res;
+
+  if(this->spline!=NULL)
+    this->spline->generate(res);
 }
 
 void COpendriveLink::set_scale_factor(double scale)
 {
+  TPoint spline_start,spline_end;
+
+  if(this->spline!=NULL)
+  {
+    this->spline->get_start_point(spline_start);
+    spline_start.x*=this->scale_factor/scale;
+    spline_start.y*=this->scale_factor/scale;
+    spline_start.curvature*=scale/this->scale_factor;
+    this->spline->set_start_point(spline_start);
+    this->spline->get_end_point(spline_end);
+    spline_end.x*=this->scale_factor/scale;
+    spline_end.y*=this->scale_factor/scale;
+    spline_end.curvature*=scale/this->scale_factor;
+    this->spline->set_end_point(spline_end);
+    this->spline->generate(this->resolution);
+  }
+
+
   this->scale_factor=scale;
+
+
 }
 
 void COpendriveLink::generate(double start_curvature,double end_curvature,double length,bool lane)
@@ -105,13 +128,13 @@ bool COpendriveLink::clean_references(node_up_ref_t &refs)
   return false;
 }
 
-void COpendriveLink::update_start_pose(TOpendriveWorldPose *start)
+TPoint COpendriveLink::update_start_pose(TOpendriveWorldPose *start)
 {
-  TPoint start_pose;
+  TPoint start_pose={0};
   double length;
 
   if(start==NULL)
-    return;
+    return start_pose;
   if(this->spline!=NULL)
   {
     length=this->spline->find_closest_point(start->x,start->y,start_pose);
@@ -119,21 +142,25 @@ void COpendriveLink::update_start_pose(TOpendriveWorldPose *start)
     this->spline->set_start_point(start_pose);
     this->spline->generate(this->resolution,length);
   }
+
+  return start_pose;
 }
 
-void COpendriveLink::update_end_pose(TOpendriveWorldPose *end)
+TPoint COpendriveLink::update_end_pose(TOpendriveWorldPose *end)
 {
-  TPoint end_pose;
+  TPoint end_pose={0};
   double length;
 
   if(end==NULL)
-    return;
+    return end_pose;
   if(this->spline!=NULL)
   {
     length=this->spline->find_closest_point(end->x,end->y,end_pose);
     this->spline->set_end_point(end_pose);
     this->spline->generate(this->resolution,length);
   }
+
+  return end_pose;
 }
 
 const COpendriveRoadNode &COpendriveLink::get_prev(void) const
diff --git a/src/opendrive_param_poly3.cpp b/src/opendrive_param_poly3.cpp
index 6405540..e57b486 100644
--- a/src/opendrive_param_poly3.cpp
+++ b/src/opendrive_param_poly3.cpp
@@ -27,7 +27,7 @@ COpendriveParamPoly3::COpendriveParamPoly3(const COpendriveParamPoly3 &object) :
   this->normalized=object.normalized;
 }
 
-bool COpendriveParamPoly3::transform_local_pose(TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
+bool COpendriveParamPoly3::transform_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
 {
   double p = (this->normalized ? track.s/((this->max_s - this->min_s)/this->scale_factor):track.s);
   double p2 = p*p;
diff --git a/src/opendrive_road.cpp b/src/opendrive_road.cpp
index 6ca93c1..9b300bd 100644
--- a/src/opendrive_road.cpp
+++ b/src/opendrive_road.cpp
@@ -741,9 +741,9 @@ std::vector<unsigned int> COpendriveRoad::get_sub_road(std::vector<unsigned int>
   // add the last segment
   node=this->nodes[path_nodes[path_nodes.size()-1]];
   link_index=node->get_closest_link(end_pose,3.14159);
-  link=node->links[link_index];
-  if(link==NULL)
+  if(link_index==(unsigned int)-1)
     throw CException(_HERE_,"The provided path has unconnected nodes");
+  link=node->links[link_index];
   segment=link->segment;
   if(new_segment_ref.find(segment)==new_segment_ref.end())
   {
@@ -786,7 +786,26 @@ std::vector<unsigned int> COpendriveRoad::get_sub_road(std::vector<unsigned int>
 
 void COpendriveRoad::get_sub_road(TOpendriveWorldPose &start_pose,double length,COpendriveRoad &road)
 {
+  segment_up_ref_t new_segment_ref;
+  lane_up_ref_t new_lane_ref;
+  node_up_ref_t new_node_ref;
+  COpendriveRoadSegment *segment,*new_segment;
+  COpendriveRoadNode *node;
+  unsigned int node_index;
+  int node_size;
 
+  // get the first segment
+/*
+  node_index=this->get_closest_nodes(start_pose,3.14159);
+  if(node_index==(unsigned int)-1)
+    throw CException(_HERE_,"Start position does not beloang to the road");
+  node=this->nodes[node_index];
+  if(node->get_num_parents()>1)
+    throw CException(_HERE_,"Road has multiple paths and no unique subroad exists");
+  segment=node->parents[0].segment;
+  node_side=segment->get_node_side(node);
+  new_segment=gegment->get_sub_sugment(new_node_ref,new_lane_ref,node_side,&start_pose,NULL);
+*/
 }
 
 void COpendriveRoad::operator=(const COpendriveRoad& object)
diff --git a/src/opendrive_road_node.cpp b/src/opendrive_road_node.cpp
index a3cfb58..f9a990f 100644
--- a/src/opendrive_road_node.cpp
+++ b/src/opendrive_road_node.cpp
@@ -22,13 +22,7 @@ COpendriveRoadNode::COpendriveRoadNode(const COpendriveRoadNode &object)
   this->resolution=object.resolution;
   this->scale_factor=object.scale_factor;
   this->pose=object.pose;
-  this->parents.resize(object.parents.size());
-  for(unsigned int i=0;i<object.parents.size();i++)
-  {
-    this->parents[i].geometry=object.parents[i].geometry->clone();
-    this->parents[i].lane=object.parents[i].lane;
-    this->parents[i].segment=object.parents[i].segment;
-  }
+  this->parents=object.parents;
   this->links.clear();
   for(unsigned int i=0;i<object.links.size();i++)
   {
@@ -40,7 +34,7 @@ COpendriveRoadNode::COpendriveRoadNode(const COpendriveRoadNode &object)
 
 bool COpendriveRoadNode::add_link(COpendriveRoadNode *node,opendrive_mark_t mark,COpendriveRoadSegment *segment,COpendriveLane *lane)
 {
-  TOpendriveWorldPose lane_end,node_pose;
+  TOpendriveWorldPose node_pose;
   double start_curvature,end_curvature,length;
   COpendriveLink *new_link;
   bool lane_found=false;
@@ -59,22 +53,13 @@ bool COpendriveRoadNode::add_link(COpendriveRoadNode *node,opendrive_mark_t mark
   node_pose=node->get_pose();
   for(unsigned int i=0;i<this->parents.size();i++)
   {
-    try{
-      lane_end=this->parents[i].lane->get_end_pose();
-      if(fabs(lane_end.x-node_pose.x)<this->resolution && fabs(lane_end.y-node_pose.y)<this->resolution)
-      {
-        this->parents[i].geometry->get_curvature(start_curvature,end_curvature);
-        length=this->parents[i].geometry->get_length();
-        if(this->parents[i].lane->get_id()>0)
-        {
-          start_curvature*=-1.0;
-          end_curvature*=-1.0;
-        }
-        lane_found=true;
-        break;
-      }
-    }
-    catch(CException &e){
+    if(this->parents[i].lane==lane && this->parents[i].segment==segment)
+    {
+      start_curvature=this->parents[i].start_curvature;
+      end_curvature=this->parents[i].end_curvature;
+      length=this->parents[i].length;
+      lane_found=true;
+      break;
     }
   }
   if(!lane_found)
@@ -156,6 +141,13 @@ void COpendriveRoadNode::set_scale_factor(double scale)
 
   for(unsigned int i=0;i<this->links.size();i++)
     this->links[i]->set_scale_factor(scale);
+
+  for(unsigned int i=0;i<this->parents.size();i++)
+  {
+    this->parents[i].start_curvature*=scale/this->scale_factor;
+    this->parents[i].end_curvature*=scale/this->scale_factor;
+    this->parents[i].length*=this->scale_factor/scale;
+  }
 }
 
 void COpendriveRoadNode::set_index(unsigned int index)
@@ -168,41 +160,18 @@ void COpendriveRoadNode::set_pose(TOpendriveWorldPose &start)
   this->pose=start;
 }
 
-void COpendriveRoadNode::add_parent(const planView::geometry_type &geom_info,COpendriveLane *lane,COpendriveRoadSegment *segment)
-{
-  COpendriveGeometry *geometry;
-  std::stringstream text;
-
-  // import geometry
-  if(geom_info.line().present())
-    geometry=new COpendriveLine();
-  else if(geom_info.spiral().present())
-    geometry=new COpendriveSpiral();
-  else if(geom_info.arc().present())
-    geometry=new COpendriveArc();
-  else if(geom_info.paramPoly3().present())
-    geometry=new COpendriveParamPoly3();
-  else
-  {
-    text << "Unsupported or missing geometry in road " << segment->get_name() << " (lane " << lane->get_id() << ")";
-    throw CException(_HERE_,text.str());
-  }
-  geometry->set_scale_factor(this->scale_factor);
-  geometry->load(geom_info);
-  this->add_parent(geometry,lane,segment);
-}
-
-void COpendriveRoadNode::add_parent(COpendriveGeometry *geometry,COpendriveLane *lane,COpendriveRoadSegment *segment)
+void COpendriveRoadNode::add_parent(COpendriveLane *lane,COpendriveRoadSegment *segment,double length,double start_curvature,double end_curvature)
 {
   TOpendriveRoadNodeParent new_parent;
 
   for(unsigned int i=0;i<this->parents.size();i++)
-    if(parents[i].geometry==geometry &&this->parents[i].lane==lane && this->parents[i].segment==segment)
+    if(this->parents[i].lane==lane && this->parents[i].segment==segment)
       return;
-
   new_parent.lane=lane;
   new_parent.segment=segment;
-  new_parent.geometry=geometry;
+  new_parent.start_curvature=start_curvature;
+  new_parent.end_curvature=end_curvature;
+  new_parent.length=length;
   this->parents.push_back(new_parent);
 }
 
@@ -227,11 +196,6 @@ TOpendriveRoadNodeParent *COpendriveRoadNode::get_parent_with_segment(const COpe
 
 void COpendriveRoadNode::free(void)
 {
-  for(unsigned int i=0;i<this->parents.size();i++)
-  {
-    delete this->parents[i].geometry;
-    this->parents[i].geometry=NULL;
-  }
   this->parents.clear();
   for(unsigned int i=0;i<this->links.size();i++)
   {
@@ -244,55 +208,6 @@ void COpendriveRoadNode::free(void)
   this->links.clear();
 }
 
-void COpendriveRoadNode::load(const planView::geometry_type &geom_info,COpendriveLane *lane,COpendriveRoadSegment *segment)
-{
-  TOpendriveTrackPose track_pose;
-  COpendriveGeometry *geometry;
-  std::stringstream text;
-
-  this->free();
-  // import geometry
-  if(geom_info.line().present())
-    geometry=new COpendriveLine();
-  else if(geom_info.spiral().present())
-    geometry=new COpendriveSpiral();
-  else if(geom_info.arc().present())
-    geometry=new COpendriveArc();
-  else if(geom_info.paramPoly3().present())
-    geometry=new COpendriveParamPoly3();
-  else
-  {
-    text << "Unsupported or missing geometry in road " << segment->get_name() << " (lane " << lane->get_id() << ")";
-    throw CException(_HERE_,text.str());
-  }
-  geometry->set_scale_factor(this->scale_factor);
-  geometry->load(geom_info);
-  // import start position
-  if(lane->get_id()<0)
-  {
-    track_pose.t=lane->get_offset()-lane->get_width()/2.0;
-    track_pose.s=0.0;
-  }
-  else
-  {
-    track_pose.t=lane->get_offset()+lane->get_width()/2.0;
-    track_pose.s=geometry->get_length();
-  }
-  track_pose.heading=0.0;
-  if(!geometry->get_world_pose(track_pose,this->pose))
-  {
-    delete geometry;
-    text << "Impossible to get world coordinates " << segment->get_name() << " (lane " << lane->get_id() << ")"; 
-    throw CException(_HERE_,text.str());
-  }
-  else
-  {
-    if(lane->get_id()>0)
-      this->pose.heading=normalize_angle(this->pose.heading+3.14159);
-  }
-  this->add_parent(geometry,lane,segment);
-}
-
 bool COpendriveRoadNode::updated(node_up_ref_t &refs)
 {
   node_up_ref_t::iterator updated_it;
@@ -350,10 +265,7 @@ void COpendriveRoadNode::clean_references(segment_up_ref_t &segment_refs,lane_up
     for(parent_it=this->parents.begin();parent_it!=this->parents.end();)
     {
       if(!parent_it->segment->updated(segment_refs) || !parent_it->lane->updated(lane_refs))
-      {
-        delete parent_it->geometry;
         parent_it=this->parents.erase(parent_it);
-      }
       else
         parent_it++;
     }
@@ -364,29 +276,11 @@ void COpendriveRoadNode::update_start_pose(COpendriveLane *lane,TOpendriveWorldP
 {
   std::vector<TOpendriveRoadNodeParent>::iterator parent_it;
   std::vector<COpendriveLink *>::iterator link_it;
-  double length;
+  double new_length;
+  TPoint new_pose;
 
   if(start==NULL)
     return;
-  // remove the references to all lanes and segments except for lane
-  for(parent_it=this->parents.begin();parent_it!=this->parents.end();)
-  {
-    if(parent_it->lane!=lane)
-    {
-      delete parent_it->geometry;
-      parent_it=this->parents.erase(parent_it);
-    }
-    else
-      parent_it++;
-  }
-  length=this->get_closest_pose(*start,this->pose,3.14159);
-  // update geometry 
-  for(unsigned int i=0;i<this->parents.size();i++)
-  {
-    if(lane->get_id()<0)
-      this->parents[i].geometry->set_start_pose(pose);
-    this->parents[i].geometry->set_max_s(this->parents[i].geometry->get_max_s()-length);
-  }
   // update the links
   for(link_it=this->links.begin();link_it!=this->links.end();)
   {
@@ -397,36 +291,35 @@ void COpendriveRoadNode::update_start_pose(COpendriveLane *lane,TOpendriveWorldP
     }
     else
     {
-      (*link_it)->update_start_pose(start);
+      new_pose=(*link_it)->update_start_pose(start);
+      new_length=(*link_it)->get_length();
       link_it++;
     }
   }
+  // remove the references to all lanes and segments except for lane
+  for(parent_it=this->parents.begin();parent_it!=this->parents.end();)
+  {
+    if(parent_it->lane!=lane)
+      parent_it=this->parents.erase(parent_it);
+    else
+    {
+      parent_it++;
+      parent_it->length=new_length;
+      parent_it->start_curvature=new_pose.curvature;
+    }
+  }
+
 }
 
 void COpendriveRoadNode::update_end_pose(COpendriveLane *lane,TOpendriveWorldPose *end)
 {
   std::vector<TOpendriveRoadNodeParent>::iterator parent_it;
   std::vector<COpendriveLink *>::iterator link_it;
-  TOpendriveWorldPose end_pose;
-  double length;
+  double new_length;
+  TPoint new_pose;
 
   if(end==NULL)
     return;
-  // remove the references to all lanes and segments except for lane
-  for(parent_it=this->parents.begin();parent_it!=this->parents.end();)
-  { 
-    if(parent_it->lane!=lane)
-    {
-      delete parent_it->geometry;
-      parent_it=this->parents.erase(parent_it);
-    }
-    else
-      parent_it++;
-  }
-  length=this->get_closest_pose(*end,end_pose,3.14159);
-  // update geometry 
-  for(unsigned int i=0;i<this->parents.size();i++)
-    this->parents[i].geometry->set_max_s(length);;
   // update the links
   for(link_it=this->links.begin();link_it!=this->links.end();)
   {
@@ -437,10 +330,23 @@ void COpendriveRoadNode::update_end_pose(COpendriveLane *lane,TOpendriveWorldPos
     }
     else
     {
-      (*link_it)->update_end_pose(end);
+      new_pose=(*link_it)->update_end_pose(end);
+      new_length=(*link_it)->get_length();
       link_it++;
     }
   }
+  // remove the references to all lanes and segments except for lane
+  for(parent_it=this->parents.begin();parent_it!=this->parents.end();)
+  { 
+    if(parent_it->lane!=lane)
+      parent_it=this->parents.erase(parent_it);
+    else
+    {
+      parent_it++;
+      parent_it->length=new_length;
+      parent_it->end_curvature=new_pose.curvature;
+    }
+  }
 }
 
 double COpendriveRoadNode::get_resolution(void) const
@@ -489,19 +395,6 @@ const COpendriveLane &COpendriveRoadNode::get_parent_lane(unsigned int index) co
   }
 }
 
-const COpendriveGeometry &COpendriveRoadNode::get_geometry(unsigned int index) const
-{
-  std::stringstream text;
-
-  if(index>=0 && index<this->parents.size())
-    return *this->parents[index].geometry;
-  else
-  {
-    text << "Invalid parent index " << index << " for node " << this->index << " (has " << this->parents.size() << " parents)";
-    throw CException(_HERE_,text.str());
-  }
-}
-
 TOpendriveWorldPose COpendriveRoadNode::get_pose(void) const
 {
   return this->pose;
@@ -660,7 +553,6 @@ std::ostream& operator<<(std::ostream& out, COpendriveRoadNode &node)
   {
     out << "      Parent " << i << ":" << std::endl;
     out << "        segment " << node.get_parent_segment(i).get_name() << " (lane " << node.get_parent_lane(i).get_id() << ")" << std::endl; 
-    out << *node.parents[i].geometry;
   }
   out << "      Number of links: " << node.links.size() << std::endl;
   for(unsigned int i=0;i<node.links.size();i++)
diff --git a/src/opendrive_road_segment.cpp b/src/opendrive_road_segment.cpp
index 80dc2bb..5b40b47 100644
--- a/src/opendrive_road_segment.cpp
+++ b/src/opendrive_road_segment.cpp
@@ -17,13 +17,11 @@ COpendriveRoadSegment::COpendriveRoadSegment()
   this->min_road_length=DEFAULT_MIN_ROAD_LENGTH;
   this->resolution=DEFAULT_RESOLUTION;
   this->scale_factor=DEFAULT_SCALE_FACTOR;
+  this->geometries.clear();
 }
 
 COpendriveRoadSegment::COpendriveRoadSegment(const COpendriveRoadSegment &object)
 {
-  COpendriveSignal *new_signal;
-  COpendriveObject *new_object;
-
   this->name=object.name;
   this->id=object.id;
   this->lanes=object.lanes;
@@ -32,22 +30,23 @@ COpendriveRoadSegment::COpendriveRoadSegment(const COpendriveRoadSegment &object
   this->nodes=object.nodes;
   this->parent_road=object.parent_road;
   this->signals.clear();
+  this->signals.resize(object.signals.size());
   for(unsigned int i=0;i<object.signals.size();i++)
-  {
-    new_signal=new COpendriveSignal(*object.signals[i]);
-    this->signals.push_back(new_signal);
-  }
-  this->objects.clear();
-  for(unsigned int i=0;i<object.objects.size();i++)
-  {
-    new_object=new COpendriveObject(*object.objects[i]);
-    this->objects.push_back(new_object);
-  }
+    this->signals[i]=new COpendriveSignal(*object.signals[i]);
+  this->objects.resize(object.objects.size());
+  for(unsigned int i=0;i<object.signals.size();i++)
+    this->objects[i]=new COpendriveObject(*object.objects[i]);
   this->connecting=object.connecting;
   this->resolution=object.resolution;
   this->scale_factor=object.scale_factor;
   this->min_road_length=object.min_road_length;
   this->center_mark=object.center_mark;
+  this->geometries.resize(object.geometries.size());
+  for(unsigned int i=0;i<object.geometries.size();i++)
+  {
+    this->geometries[i].opendrive=object.geometries[i].opendrive->clone();
+    this->geometries[i].spline=new CG2Spline(*object.geometries[i].spline);
+  }
 }
 
 void COpendriveRoadSegment::free(void)
@@ -69,6 +68,14 @@ void COpendriveRoadSegment::free(void)
   }
   this->objects.clear();
   this->connecting.clear();
+  for(unsigned int i=0;i<this->geometries.size();i++)
+  {
+    delete this->geometries[i].opendrive;
+    this->geometries[i].opendrive=NULL;
+    delete this->geometries[i].spline;
+    this->geometries[i].spline=NULL;
+  }
+  this->geometries.clear();
 }
 
 void COpendriveRoadSegment::set_resolution(double res)
@@ -79,6 +86,9 @@ void COpendriveRoadSegment::set_resolution(double res)
 
   for(lane_it=this->lanes.begin();lane_it!=this->lanes.end();++lane_it)
     lane_it->second->set_resolution(res);
+
+  for(unsigned int i=0;i<this->geometries.size();i++)
+    this->geometries[i].spline->generate(res);
 }
 
 void COpendriveRoadSegment::set_scale_factor(double scale)
@@ -93,6 +103,9 @@ void COpendriveRoadSegment::set_scale_factor(double scale)
     this->signals[i]->set_scale_factor(scale);
   for(unsigned int i=0;i<this->objects.size();i++)
     this->objects[i]->set_scale_factor(scale);
+
+  for(unsigned int i=0;i<this->geometries.size();i++)
+    this->geometries[i].opendrive->set_scale_factor(scale);
 }
 
 void COpendriveRoadSegment::set_min_road_length(double length)
@@ -120,6 +133,62 @@ void COpendriveRoadSegment::set_center_mark(opendrive_mark_t mark)
   this->center_mark=mark;
 }
 
+void COpendriveRoadSegment::add_geometries(OpenDRIVE::road_type &road_info)
+{
+  planView::geometry_iterator geom_info;
+  TOpendriveRoadSegmentGeometry geometry;
+  TOpendriveWorldPose start_pose,end_pose;
+  TPoint spline_start,spline_end;
+  double start_curvature,end_curvature;
+  std::stringstream error;
+
+  for(unsigned int i=0;i<this->geometries.size();i++)
+  {
+    delete this->geometries[i].opendrive;
+    delete this->geometries[i].spline;
+  }
+  this->geometries.clear();
+  for(geom_info=road_info.planView().geometry().begin(); geom_info!=road_info.planView().geometry().end(); ++geom_info)
+  {
+    // import geometry
+    if(geom_info->line().present())
+      geometry.opendrive=new COpendriveLine();
+    else if(geom_info->spiral().present())
+      geometry.opendrive=new COpendriveSpiral();
+    else if(geom_info->arc().present())
+      geometry.opendrive=new COpendriveArc();
+    else if(geom_info->paramPoly3().present())
+      geometry.opendrive=new COpendriveParamPoly3();
+    else
+    {
+      error << "Unsupported or missing geometry in road " << this->name;
+      throw CException(_HERE_,error.str());
+    }
+    geometry.opendrive->set_scale_factor(this->scale_factor);
+    geometry.opendrive->load(*geom_info);
+    if(geometry.opendrive->get_length()>this->min_road_length)
+    {
+      // create spline
+      geometry.spline=new CG2Spline();
+      start_pose=geometry.opendrive->get_start_pose();
+      end_pose=geometry.opendrive->get_end_pose();
+      geometry.opendrive->get_curvature(start_curvature,end_curvature);
+      spline_start.x=start_pose.x;
+      spline_start.y=start_pose.y;
+      spline_start.heading=start_pose.heading;
+      spline_start.curvature=start_curvature;
+      geometry.spline->set_start_point(spline_start);
+      spline_end.x=end_pose.x;
+      spline_end.y=end_pose.y;
+      spline_end.heading=end_pose.heading;
+      spline_end.curvature=end_curvature;
+      geometry.spline->set_end_point(spline_end);
+      geometry.spline->generate(this->resolution,geometry.opendrive->get_length());
+      this->geometries.push_back(geometry);
+    }
+  }
+}
+
 bool COpendriveRoadSegment::updated(segment_up_ref_t &refs)
 {
   segment_up_ref_t::iterator updated_it;
@@ -298,36 +367,36 @@ void COpendriveRoadSegment::remove_lane(COpendriveLane *lane)
   }
 }
 
-void COpendriveRoadSegment::add_nodes(OpenDRIVE::road_type &road_info)
+void COpendriveRoadSegment::add_nodes(void)
 {
-  planView::geometry_iterator geom_it;
   double lane_offset;
 
-  for(geom_it=road_info.planView().geometry().begin(); geom_it!=road_info.planView().geometry().end(); ++geom_it)
+  for(unsigned int j=0;j<this->geometries.size();j++)
   {
     lane_offset=0.0;
     for(int i=-1;i>=-this->num_right_lanes;i--)
     {
       this->lanes[i]->set_offset(lane_offset);
-      this->add_node(*geom_it,this->lanes[i]);
+      this->add_node(this->geometries[j],this->lanes[i]);
       lane_offset-=this->lanes[i]->width;
     }
   }
-  for(geom_it=road_info.planView().geometry().end(); geom_it!=road_info.planView().geometry().begin();)
+  for(unsigned int j=0;j<this->geometries.size();j++)
   {
-    geom_it--;
     lane_offset=0.0;
     for(int i=1;i<=this->num_left_lanes;i++)
     {
       this->lanes[i]->set_offset(lane_offset);
-      this->add_node(*geom_it,this->lanes[i]);
+      this->add_node(this->geometries[this->geometries.size()-1-j],this->lanes[i]);
       lane_offset+=this->lanes[i]->width;
     }
   }
 }
 
-void COpendriveRoadSegment::add_node(const planView::geometry_type &geom_info,COpendriveLane *lane)
+void COpendriveRoadSegment::add_node(TOpendriveRoadSegmentGeometry &geometry,COpendriveLane *lane)
 {
+  TOpendriveTrackPose track_pose;
+  double start_curvature,end_curvature,length;
   COpendriveRoadNode *new_node;
   TOpendriveWorldPose node_pose;
   unsigned int node_index;
@@ -337,31 +406,54 @@ void COpendriveRoadSegment::add_node(const planView::geometry_type &geom_info,CO
     new_node=new COpendriveRoadNode();
     new_node->set_resolution(this->resolution);
     new_node->set_scale_factor(this->scale_factor);
-    new_node->load(geom_info,lane,this);
-    if(new_node->get_geometry(0).get_length()>this->min_road_length)
+    // import start position
+    track_pose.t=lane->get_center_offset();
+    track_pose.heading=0.0;
+    if(lane->get_id()<0)
     {
-      node_pose=new_node->get_pose();
-      if(this->parent_road->node_exists_at(node_pose))
-      {
-        delete new_node;
-        new_node=this->parent_road->get_node_at(node_pose);
-        new_node->add_parent(geom_info,lane,this);
-      }
-      else
+      track_pose.s=0.0;
+      geometry.opendrive->get_world_pose(track_pose,node_pose);
+    }
+    else
+    {
+      track_pose.s=geometry.opendrive->get_length();
+      geometry.opendrive->get_world_pose(track_pose,node_pose);
+      node_pose.heading=normalize_angle(node_pose.heading+3.14159);
+    }
+    new_node->set_pose(node_pose);
+    if(this->parent_road->node_exists_at(node_pose))
+    {
+      delete new_node;
+      new_node=this->parent_road->get_node_at(node_pose);
+    }
+    else
+    {
+      node_index=this->parent_road->add_node(new_node);
+      new_node->set_index(node_index);
+    }
+    geometry.opendrive->get_curvature(start_curvature,end_curvature);
+    if(start_curvature>0)
+      start_curvature=1.0/((1.0/start_curvature)-lane->get_center_offset());
+    else
+      start_curvature=1.0/((1.0/start_curvature)+lane->get_center_offset());
+    if(end_curvature>0)
+      end_curvature=1.0/((1.0/end_curvature)-lane->get_center_offset());
+    else
+      end_curvature=1.0/((1.0/end_curvature)+lane->get_center_offset());
+    length=geometry.opendrive->get_length();
+    if(lane->get_id()<0)
+      new_node->add_parent(lane,this,length,start_curvature,end_curvature);
+    else
+      new_node->add_parent(lane,this,length,-end_curvature,-start_curvature);
+    for(unsigned int i=0;i<this->nodes.size();i++)
+      if(this->nodes[i]==new_node)
       {
-        node_index=this->parent_road->add_node(new_node);
-        new_node->set_index(node_index);
+        exist=true;
+        break;
       }
-      for(unsigned int i=0;i<this->nodes.size();i++)
-        if(this->nodes[i]==new_node)
-        {
-          exist=true;
-          break;
-        }
-      if(!exist)
-        this->nodes.push_back(new_node);
-      lane->add_node(new_node);
-    }
+    if(!exist)
+      this->nodes.push_back(new_node);
+    lane->add_node(new_node);
   }catch(CException &e){
     this->free();
     if(!this->parent_road->remove_node(new_node))
@@ -595,6 +687,9 @@ COpendriveRoadSegment *COpendriveRoadSegment::get_sub_segment(node_up_ref_t &new
   COpendriveRoadSegment *new_segment;
   std::vector<COpendriveRoadNode *>::iterator node_it;
   node_up_ref_t::iterator node_ref_it;
+  std::vector<TOpendriveRoadSegmentGeometry>::iterator geom_it;
+  TPoint new_point;
+  double length;
 
   if(start==NULL && end==NULL)
     return this->clone(new_node_ref,new_lane_ref);
@@ -610,7 +705,41 @@ COpendriveRoadSegment *COpendriveRoadSegment::get_sub_segment(node_up_ref_t &new
     new_lane_ref[lane_it->second]=new_lane;
   }
   new_segment->update_references(new_segment_ref,new_lane_ref,new_node_ref);
-  // update signals and objects
+  // update geometry
+  for(geom_it=this->geometries.begin();geom_it!=this->geometries.end();)
+  {
+    if(start!=NULL)
+    {
+      length=geom_it->spline->find_closest_point(start->x,start->y,new_point);
+      if(length>geom_it->opendrive->get_length())
+        geom_it=this->geometries.erase(geom_it);
+      else
+      {
+        geom_it->spline->set_start_point(new_point);
+        geom_it->spline->generate(this->resolution);
+        geom_it->opendrive->set_start_pose(*start);
+        geom_it->opendrive->set_max_s(geom_it->opendrive->get_max_s()-length);
+        break;
+      }
+    }
+  }
+  for(geom_it=this->geometries.begin();geom_it!=this->geometries.end();)
+  {
+    if(end!=NULL)
+    {
+      length=geom_it->spline->find_closest_point(end->x,end->y,new_point);
+      if(length<geom_it->opendrive->get_length())
+      {
+        geom_it->spline->set_end_point(new_point);
+        geom_it->spline->generate(this->resolution);
+        geom_it->opendrive->set_max_s(length);;
+        geom_it=this->geometries.erase(geom_it+1,this->geometries.end());
+        break;
+      }
+      else
+        geom_it++;
+    }
+  }
 
   return new_segment; 
 }
@@ -665,11 +794,13 @@ void COpendriveRoadSegment::load(OpenDRIVE::road_type &road_info)
   else
     lane_section=road_info.lanes().laneSection().begin();
 
-  // add lanes
   try{
+    // add lanes
     this->add_lanes(*lane_section);
+    // add geometries
+    this->add_geometries(road_info);
     // add road nodes
-    this->add_nodes(road_info);
+    this->add_nodes();
     // link lanes
     this->link_neightbour_lanes(*lane_section);
     // add road signals
@@ -812,6 +943,16 @@ const COpendriveRoadSegment &COpendriveRoadSegment::get_connecting(unsigned int
   }
 }
 
+double COpendriveRoadSegment::get_length(void)
+{
+  double length=0.0;
+
+  for(unsigned int i=0;i<this->geometries.size();i++)
+    length+=this->geometries[i].opendrive->get_length();
+
+  return length;
+}
+
 TOpendriveLocalPose COpendriveRoadSegment::transform_to_local_pose(const TOpendriveTrackPose &track)
 {
   TOpendriveTrackPose pose;
@@ -824,16 +965,23 @@ TOpendriveLocalPose COpendriveRoadSegment::transform_to_local_pose(const TOpendr
     throw CException(_HERE_,error.str());
   }
   pose=track;
-  if(this->num_right_lanes>0)
-    local=this->lanes[-1]->transform_to_local_pose(pose);
-  else
+  for(unsigned int i=0;i<this->geometries.size();i++)
   {
-    pose.s=this->lanes[1]->get_length()-track.s;
-    pose.heading=normalize_angle(track.heading+3.14159);
-    local=this->lanes[1]->transform_to_local_pose(pose);
+    if((pose.s-this->geometries[i].opendrive->get_length())<=this->resolution)
+    {
+      if(!this->geometries[i].opendrive->get_local_pose(pose,local))
+      {
+        error << "Impossible to transform to local coordinates pose (s=" << track.s << ",t=" << track.t << ",heading=" << track.heading << ") in segment " << this->name;
+        throw CException(_HERE_,error.str());
+      }
+      return local;
+    }
+    else
+      pose.s-=this->geometries[i].opendrive->get_length();
   }
 
-  return local;
+  error << "Track pose (s=" << track.s << ",t=" << track.t << ",heading=" << track.heading << ") does not belong to segment " << this->name;
+  throw CException(_HERE_,error.str());
 }
 
 TOpendriveWorldPose COpendriveRoadSegment::transform_to_world_pose(const TOpendriveTrackPose &track)
@@ -848,16 +996,23 @@ TOpendriveWorldPose COpendriveRoadSegment::transform_to_world_pose(const TOpendr
     throw CException(_HERE_,error.str());
   }
   pose=track;
-  if(this->num_right_lanes>0)
-    world=this->lanes[-1]->transform_to_world_pose(pose);
-  else
+  for(unsigned int i=0;i<this->geometries.size();i++)
   {
-    pose.s=this->lanes[1]->get_length()-track.s;
-    pose.heading=normalize_angle(track.heading+3.14159);
-    world=this->lanes[1]->transform_to_world_pose(pose);
+    if((pose.s-this->geometries[i].opendrive->get_length())<=this->resolution)
+    {
+      if(!this->geometries[i].opendrive->get_world_pose(pose,world))
+      {
+        error << "Impossible to transform to world coordinates pose (s=" << track.s << ",t=" << track.t << ",heading=" << track.heading << ") in segment " << this->name;
+        throw CException(_HERE_,error.str());
+      }
+      return world;
+    }
+    else
+      pose.s-=this->geometries[i].opendrive->get_length();
   }
 
-  return world;
+  error << "Track pose (s=" << track.s << ",t=" << track.t << ",heading=" << track.heading << ") does not belong to segment " << this->name;
+  throw CException(_HERE_,error.str());
 }
 
 std::ostream& operator<<(std::ostream& out, COpendriveRoadSegment &segment)
diff --git a/src/opendrive_spiral.cpp b/src/opendrive_spiral.cpp
index 1e21a50..089ad95 100644
--- a/src/opendrive_spiral.cpp
+++ b/src/opendrive_spiral.cpp
@@ -12,7 +12,7 @@ COpendriveSpiral::COpendriveSpiral(const COpendriveSpiral &object) : COpendriveG
   this->end_curvature=object.end_curvature;
 }
 
-bool COpendriveSpiral::transform_local_pose(TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
+bool COpendriveSpiral::transform_local_pose(const TOpendriveTrackPose &track,TOpendriveLocalPose &local) const
 {
   return true;
 }
-- 
GitLab