From a943f5efb1391c17ca15143b75f3ccb12b039053 Mon Sep 17 00:00:00 2001
From: Sergi Hernandez Juan <shernand@iri.upc.edu>
Date: Wed, 16 Dec 2020 18:20:23 +0100
Subject: [PATCH] Added support to process the junctions. Added support to link
 road segments.

---
 include/opendrive_lane.h         |   4 +-
 include/opendrive_link.h         |   2 +-
 include/opendrive_road.h         |   4 +-
 include/opendrive_road_node.h    |   3 +
 include/opendrive_road_segment.h |   8 +-
 src/opendrive_lane.cpp           | 112 ++++++++++++++----------
 src/opendrive_link.cpp           |  83 ++++++++++++++----
 src/opendrive_road.cpp           | 133 +++++++++++++++++++++++++++-
 src/opendrive_road_node.cpp      |  22 ++++-
 src/opendrive_road_segment.cpp   | 145 ++++++++++++++++++++-----------
 10 files changed, 391 insertions(+), 125 deletions(-)

diff --git a/include/opendrive_lane.h b/include/opendrive_lane.h
index 33e2120..f3b9a24 100644
--- a/include/opendrive_lane.h
+++ b/include/opendrive_lane.h
@@ -27,8 +27,8 @@ class COpendriveLane
     double offset;
     int id;
   protected:
-    void link_left_lane(COpendriveLane *lane);
-    void link_right_lane(COpendriveLane *lane);
+    void link_neightbour_lane(COpendriveLane *lane);
+    void link_lane(COpendriveLane *lane,opendrive_mark_t mark);
     void add_node(COpendriveRoadNode *node);
     void set_resolution(double res);
     void set_scale_factor(double scale);
diff --git a/include/opendrive_link.h b/include/opendrive_link.h
index 5f5478b..9dafa58 100644
--- a/include/opendrive_link.h
+++ b/include/opendrive_link.h
@@ -1,4 +1,4 @@
-#ifndef _OPNEDRIVE_LINK_H
+#ifndef _OPENDRIVE_LINK_H
 #define _OPENDRIVE_LINK_H
 
 #include "g2_spline.h"
diff --git a/include/opendrive_road.h b/include/opendrive_road.h
index 0d75497..23f002f 100644
--- a/include/opendrive_road.h
+++ b/include/opendrive_road.h
@@ -15,7 +15,9 @@ class COpendriveRoad
     double scale_factor;
     double min_road_length;
   protected:
-    void add_road_nodes(std::unique_ptr<OpenDRIVE::road_type> &road_info);
+    COpendriveRoadSegment &operator[](std::string &key);
+    void link_segments(OpenDRIVE &open_drive);
+    std::string get_junction_road_id(OpenDRIVE &open_drive,std::string &incoming,std::string &connecting);
   public:
     COpendriveRoad();
     COpendriveRoad(const COpendriveRoad& object);
diff --git a/include/opendrive_road_node.h b/include/opendrive_road_node.h
index 0e87653..2db3d6e 100644
--- a/include/opendrive_road_node.h
+++ b/include/opendrive_road_node.h
@@ -18,16 +18,19 @@ class COpendriveRoadNode
     TOpendriveWorldPoint start_point;
     COpendriveLane *lane;
     COpendriveGeometry *geometry;
+    unsigned int index;
   protected:
     void add_link(COpendriveRoadNode *node,opendrive_mark_t mark);
     void set_resolution(double res);
     void set_scale_factor(double scale);
+    void set_index(unsigned int index);
   public:
     COpendriveRoadNode();
     COpendriveRoadNode(const COpendriveRoadNode &object);
     void load(const planView::geometry_type &node_info,COpendriveLane *lane);
     double get_resolution(void) const;
     double get_scale_factor(void) const;
+    unsigned int get_index(void) const;
     TOpendriveWorldPoint get_start_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 b428549..712f1ee 100644
--- a/include/opendrive_road_segment.h
+++ b/include/opendrive_road_segment.h
@@ -19,8 +19,8 @@ class COpendriveRoadSegment
     double resolution;
     double scale_factor;
     double min_road_length;
-    unsigned int num_right_lanes;
-    unsigned int num_left_lanes;
+    int num_right_lanes;
+    int num_left_lanes;
     std::vector<COpendriveSignal *> signals;
     std::vector<COpendriveObject *> objects;
     std::vector<COpendriveRoadSegment *> next;
@@ -35,7 +35,9 @@ class COpendriveRoadSegment
     void update_references(std::map<COpendriveRoadSegment *,COpendriveRoadSegment *> refs);
     void add_lanes(lanes::laneSection_type &lane_section);
     void add_nodes(OpenDRIVE::road_type &road_info);
-    void link_lanes(lanes::laneSection_type &lane_section);
+    void link_neightbour_lanes(lanes::laneSection_type &lane_section);
+    void link_segment(COpendriveRoadSegment &segment);
+    void link_segment(COpendriveRoadSegment &segment,int from, int to);
   public:
     COpendriveRoadSegment();
     COpendriveRoadSegment(const COpendriveRoadSegment &object);
diff --git a/src/opendrive_lane.cpp b/src/opendrive_lane.cpp
index 6720c1e..32c500c 100644
--- a/src/opendrive_lane.cpp
+++ b/src/opendrive_lane.cpp
@@ -40,38 +40,52 @@ COpendriveLane::COpendriveLane(const COpendriveLane &object)
   this->id=object.id;
 }
 
-void COpendriveLane::link_left_lane(COpendriveLane *lane)
+void COpendriveLane::link_neightbour_lane(COpendriveLane *lane)
 {
   if(lane!=NULL)
   {
     if(this->get_num_nodes()!=lane->get_num_nodes())
-      throw CException(_HERE_,"Impossible to link lanes because they have different number of nodes");
-    for(unsigned int i=1;i<this->get_num_nodes();i++)
+      throw CException(_HERE_,"Impossible to liink lanes because they have different number of nodes");
+    if(this->get_num_nodes()>0 && lane->get_num_nodes()>0)
     {
-      this->nodes[i]->add_link(lane->nodes[i-1],this->left_mark);
-      lane->nodes[i]->add_link(this->nodes[i-1],this->left_mark);
-    } 
-    this->left_lane=lane;
+      if(this->id*lane->get_id()<0) // oposite directions
+      {
+        for(unsigned int i=0;i<this->get_num_nodes();i++)
+        {
+          this->nodes[i]->add_link(lane->nodes[lane->get_num_nodes()-i-1],this->left_mark);
+          lane->nodes[lane->get_num_nodes()-i-1]->add_link(this->nodes[i],this->left_mark);
+          lane->right_mark=this->left_mark;
+        }
+      }
+      else
+      {
+        for(unsigned int i=0;i<this->get_num_nodes()-1;i++)
+        {
+          this->nodes[i]->add_link(lane->nodes[i+1],this->left_mark);
+          lane->nodes[i]->add_link(this->nodes[i+1],this->left_mark);
+          if(this->id>0)// left lanes
+            this->right_mark=lane->left_mark;
+          else// right lanes
+            this->left_mark=lane->right_mark;
+        }
+      } 
+      this->left_lane=lane;
+      lane->right_lane=this;
+    }
+    else
+      throw CException(_HERE_,"One of the lanes to link has no nodes");
   }
-  else
-    this->left_lane=NULL;
 }
 
-void COpendriveLane::link_right_lane(COpendriveLane *lane)
+void COpendriveLane::link_lane(COpendriveLane *lane,opendrive_mark_t mark)
 {
   if(lane!=NULL)
   {
-    if(this->get_num_nodes()!=lane->get_num_nodes())
-      throw CException(_HERE_,"Impossible to link lanes because they have different number of nodes");
-    for(unsigned int i=1;i<this->get_num_nodes();i++)
-    {
-      this->nodes[i]->add_link(lane->nodes[i-1],this->right_mark);
-      lane->nodes[i]->add_link(this->nodes[i-1],this->right_mark);
-    } 
-    this->right_lane=lane;
+    if(this->get_num_nodes()>0 && lane->get_num_nodes()>0)
+      this->nodes[this->nodes.size()-1]->add_link(lane->nodes[0],mark);
+    else 
+      throw CException(_HERE_,"One of the lanes to link has no nodes");
   }
-  else
-    this->right_lane=NULL;
 }
 
 void COpendriveLane::add_node(COpendriveRoadNode *node)
@@ -80,6 +94,7 @@ void COpendriveLane::add_node(COpendriveRoadNode *node)
     if(this->nodes[i]==node)
       return;
   // add the new node
+  node->set_index(this->nodes.size());
   this->nodes.push_back(node);
   // link the new node with the previous one in the current lane, if any
   if(this->nodes.size()>1)
@@ -143,32 +158,37 @@ void COpendriveLane::load(const right::lane_type &lane_info,COpendriveRoadSegmen
   }
   this->speed=lane_info.speed().begin()->max().get();
   //lane mark
-  if(lane_info.roadMark().size()!=1)
+  if(lane_info.roadMark().size()==0)
+    mark=OD_MARK_NONE;
+  else if(lane_info.roadMark().size()>1)
   {
     error << "Only one road mark supported for lane " << this->id;
     throw CException(_HERE_,error.str());
   }
-  if(lane_info.roadMark().begin()->type().present())
+  else if(lane_info.roadMark().size()==1)
   {
-    if(lane_info.roadMark().begin()->type().get()=="none")
-      mark=OD_MARK_NONE;
-    else if(lane_info.roadMark().begin()->type().get()=="solid")
-      mark=OD_MARK_SOLID;
-    else if(lane_info.roadMark().begin()->type().get()=="broken")
-      mark=OD_MARK_BROKEN;
-    else if(lane_info.roadMark().begin()->type().get()=="solid_solid")
-      mark=OD_MARK_SOLID_SOLID;
-    else if(lane_info.roadMark().begin()->type().get()=="solid_broken")
-      mark=OD_MARK_SOLID_BROKEN;
-    else if(lane_info.roadMark().begin()->type().get()=="broken_solid")
-      mark=OD_MARK_BROKEN_SOLID;
-    else if(lane_info.roadMark().begin()->type().get()=="broken_broken")
-      mark=OD_MARK_BROKEN_BROKEN;
+    if(lane_info.roadMark().begin()->type1().present())
+    {
+      if(lane_info.roadMark().begin()->type1().get()=="none")
+        mark=OD_MARK_NONE;
+      else if(lane_info.roadMark().begin()->type1().get()=="solid")
+        mark=OD_MARK_SOLID;
+      else if(lane_info.roadMark().begin()->type1().get()=="broken")
+        mark=OD_MARK_BROKEN;
+      else if(lane_info.roadMark().begin()->type1().get()=="solid_solid")
+        mark=OD_MARK_SOLID_SOLID;
+      else if(lane_info.roadMark().begin()->type1().get()=="solid_broken")
+        mark=OD_MARK_SOLID_BROKEN;
+      else if(lane_info.roadMark().begin()->type1().get()=="broken_solid")
+        mark=OD_MARK_BROKEN_SOLID;
+      else if(lane_info.roadMark().begin()->type1().get()=="broken_broken")
+        mark=OD_MARK_BROKEN_BROKEN;
+      else
+        mark=OD_MARK_NONE;
+    }
     else
       mark=OD_MARK_NONE;
   }
-  else
-    mark=OD_MARK_NONE;
   if(this->id<0)//right lanes
     this->right_mark=mark;
   else
@@ -236,17 +256,17 @@ void COpendriveLane::operator=(const COpendriveLane &object)
 
 std::ostream& operator<<(std::ostream& out, COpendriveLane &lane)
 {
-  out << "    id: " << lane.id << " (offset: " << lane.offset << ")" << std::endl;
+  out << "  Lane: " << lane.id << " (offset: " << lane.offset << ")" << std::endl;
   out << "    width: " << lane.get_width() << std::endl;
   out << "    speed: " << lane.get_speed() << std::endl;
   if(lane.segment!=NULL)
     out << "    Parent road segment: " << lane.segment->get_name() << std::endl;
   else 
     out << "    No parent segment" << std::endl;
-  if(lane.left_lane!=NULL)
-    out << "    No left lane (" << std::endl;
+  if(lane.left_lane==NULL)
+    out << "    No left lane (";
   else
-    out << "    Left lane " << lane.get_id() << " (" << std::endl;
+    out << "    Left lane " << lane.left_lane->get_id() << " (";
   switch(lane.left_mark)
   {
     case OD_MARK_NONE:
@@ -271,10 +291,10 @@ std::ostream& operator<<(std::ostream& out, COpendriveLane &lane)
       out << "broken broken)" << std::endl;
       break;
   }
-  if(lane.right_lane!=NULL)
-    out << "    No right lane (" << std::endl;
+  if(lane.right_lane==NULL)
+    out << "    No right lane (";
   else
-    out << "    Right lane " << lane.get_id() << " (" << std::endl;
+    out << "    Right lane " << lane.right_lane->get_id() << " (";
   switch(lane.right_mark)
   {
     case OD_MARK_NONE:
@@ -301,7 +321,7 @@ std::ostream& operator<<(std::ostream& out, COpendriveLane &lane)
   }
   out << "    Number of nodes: " << lane.nodes.size() << std::endl;
   for(unsigned int i=0;i<lane.nodes.size();i++)
-    out << *lane.nodes[i] << std::endl;
+    out << *lane.nodes[i];
 
   return out;
 }
diff --git a/src/opendrive_link.cpp b/src/opendrive_link.cpp
index 05c4e89..4b68da2 100644
--- a/src/opendrive_link.cpp
+++ b/src/opendrive_link.cpp
@@ -1,38 +1,49 @@
 #include "opendrive_link.h"
+#include "opendrive_road_node.h"
 
 COpendriveLink::COpendriveLink()
 {
-
+  this->prev=NULL;
+  this->next=NULL;
+  this->spline=NULL;
+  this->mark=OD_MARK_NONE;
+  this->resolution=DEFAULT_RESOLUTION;
+  this->scale_factor=DEFAULT_SCALE_FACTOR;
 }
 
 COpendriveLink::COpendriveLink(const COpendriveLink &object)
 {
-
+  this->prev=object.prev;
+  this->next=object.next;
+  this->spline=new CG2Spline(*object.spline);
+  this->mark=object.mark;
+  this->resolution=object.resolution;
+  this->scale_factor=object.scale_factor;
 }
 
 void COpendriveLink::set_prev(COpendriveRoadNode *node)
 {
-
+  this->prev=node;
 }
 
 void COpendriveLink::set_next(COpendriveRoadNode *node)
 {
-
+  this->next=node;
 }
 
 void COpendriveLink::set_road_mark(opendrive_mark_t mark)
 {
-
+  this->mark=mark;
 }
 
 void COpendriveLink::set_resolution(double res)
 {
-
+  this->resolution=res;
 }
 
 void COpendriveLink::set_scale_factor(double scale)
 {
-
+  this->scale_factor=scale;
 }
 
 void COpendriveLink::generate(void)
@@ -42,27 +53,27 @@ void COpendriveLink::generate(void)
 
 const COpendriveRoadNode &COpendriveLink::get_prev(void) const
 {
-
+  return *this->prev;
 }
 
 const COpendriveRoadNode &COpendriveLink::get_next(void) const
 {
-
+  return *this->next;
 }
 
 opendrive_mark_t COpendriveLink::get_road_mark(void) const
 {
-
+  return this->mark;
 }
 
 double COpendriveLink::get_resolution(void) const
 {
-
+  return this->resolution;
 }
 
 double COpendriveLink::get_scale_factor(void) const
 {
-
+  return this->scale_factor;
 }
 
 double COpendriveLink::find_closest_world_point(TOpendriveWorldPoint &world,TPoint &point)
@@ -92,16 +103,58 @@ double COpendriveLink::get_length(void) const
 
 void COpendriveLink::operator=(const COpendriveLink &object)
 {
-
+  this->prev=object.prev;
+  this->next=object.next;
+  this->spline=new CG2Spline(*object.spline);
+  this->mark=object.mark;
+  this->resolution=object.resolution;
+  this->scale_factor=object.scale_factor;
 }
 
 std::ostream& operator<<(std::ostream& out, COpendriveLink &link)
 {
-
+  out << "        Previous node: " << link.get_prev().get_index() << " of lane " << link.get_prev().get_lane().get_id() << " of road " << link.get_prev().get_lane().get_segment().get_name() << std::endl;
+  out << "        Next node: " << link.get_next().get_index() << " of lane " << link.get_next().get_lane().get_id() << " of road " << link.get_next().get_lane().get_segment().get_name() << std::endl;
+  out << "        Road mark: ";
+  switch(link.mark)
+  {
+    case OD_MARK_NONE:
+      out << "no mark" << std::endl;
+      break;
+    case OD_MARK_SOLID:
+      out << "solid" << std::endl;
+      break;
+    case OD_MARK_BROKEN:
+      out << "broken" << std::endl;
+      break;
+    case OD_MARK_SOLID_SOLID:
+      out << "solid solid" << std::endl;
+      break;
+    case OD_MARK_SOLID_BROKEN:
+      out << "solid broken" << std::endl;
+      break;
+    case OD_MARK_BROKEN_SOLID:
+      out << "broken solid" << std::endl;
+      break;
+    case OD_MARK_BROKEN_BROKEN:
+      out << "broken broken" << std::endl;
+      break;
+  }
+
+  return out;
 }
 
 COpendriveLink::~COpendriveLink()
 {
-
+  this->prev=NULL;
+  this->next=NULL;
+  if(this->spline!=NULL)
+  {
+    delete this->spline;
+    this->spline=NULL;
+  }
+  this->mark=OD_MARK_NONE;
+  this->resolution=DEFAULT_RESOLUTION;
+  this->scale_factor=DEFAULT_SCALE_FACTOR;
 }
 
diff --git a/src/opendrive_road.cpp b/src/opendrive_road.cpp
index 5c33438..ae0ca2e 100644
--- a/src/opendrive_road.cpp
+++ b/src/opendrive_road.cpp
@@ -30,10 +30,88 @@ COpendriveRoad::COpendriveRoad(const COpendriveRoad& object)
     this->segments[i]->update_references(new_references);
 }
 
+COpendriveRoadSegment &COpendriveRoad::operator[](std::string &key)
+{
+  for(unsigned int i=0;i<this->segments.size();i++)
+  {
+    if(this->segments[i]->get_id()==(unsigned int)std::stoi(key))
+      return *this->segments[i];
+  }
+
+  throw CException(_HERE_,"No road segment with the given ID");
+}
+
+void COpendriveRoad::link_segments(OpenDRIVE &open_drive)
+{
+  for(OpenDRIVE::road_iterator road_it(open_drive.road().begin());road_it!=open_drive.road().end();++road_it)
+  {
+    COpendriveRoadSegment &segment=(*this)[road_it->id().get()];
+    if(std::stoi(road_it->junction().get())==-1)// process only non junction road segments
+    {
+      // get predecessor
+      if(road_it->lane_link().present())
+      {
+        if(road_it->lane_link().get().predecessor().present())// predecessor present
+        {
+          if(road_it->lane_link().get().predecessor().get().elementType().get()=="road")
+          {
+            COpendriveRoadSegment &link_segment=(*this)[road_it->lane_link().get().predecessor().get().elementId().get()];
+            link_segment.link_segment(segment);
+          }
+          // else ignore juntions
+        }
+        if(road_it->lane_link().get().successor().present())// predecessor present
+        {
+          if(road_it->lane_link().get().successor().get().elementType().get()=="road")
+          {
+            COpendriveRoadSegment &link_segment=(*this)[road_it->lane_link().get().successor().get().elementId().get()];
+            segment.link_segment(link_segment);
+          }
+          // else ignore juntions
+        }
+      }
+    }
+  }
+}
+
+std::string COpendriveRoad::get_junction_road_id(OpenDRIVE &open_drive,std::string &incoming,std::string &connecting)
+{
+  bool predecessor_match,successor_match;
+  for (OpenDRIVE::road_iterator road_it(open_drive.road().begin()); road_it != open_drive.road().end(); ++road_it)
+  {
+    predecessor_match=false;
+    successor_match=false;
+    if(std::stoi(road_it->junction().get())!=-1)// process only junction road segments
+    {
+      // get predecessor
+      if(road_it->lane_link().present())
+      {
+        if(road_it->lane_link().get().predecessor().present())// predecessor present
+        {
+          if(road_it->lane_link().get().predecessor().get().elementType().get()=="road")
+            if(road_it->lane_link().get().predecessor().get().elementId().get()==incoming)
+              predecessor_match=true;
+        }
+        if(road_it->lane_link().get().successor().present())// predecessor present
+        {
+          if(road_it->lane_link().get().successor().get().elementType().get()=="road")
+          {
+            if(road_it->lane_link().get().successor().get().elementId().get()==connecting)
+              successor_match=true;
+          }
+        }
+      }
+    }
+    if(predecessor_match && successor_match)
+      return road_it->id().get();
+  }
+
+  return std::string("");
+}
+
 void COpendriveRoad::load(const std::string &filename)
 {
   struct stat buffer;
-  COpendriveRoadSegment *segment;
 
   if(stat(filename.c_str(),&buffer)==0)
   {
@@ -47,7 +125,7 @@ void COpendriveRoad::load(const std::string &filename)
       for (OpenDRIVE::road_iterator road_it(open_drive->road().begin()); road_it != open_drive->road().end(); ++road_it)
       {
         try{
-          segment=new COpendriveRoadSegment();
+          COpendriveRoadSegment *segment=new COpendriveRoadSegment();
           segment->set_resolution(this->resolution);
           segment->set_scale_factor(this->scale_factor);
           segment->load(*road_it);
@@ -56,6 +134,55 @@ void COpendriveRoad::load(const std::string &filename)
           std::cout << e.what() << std::endl;
         }
       }
+      // link segments
+      this->link_segments(*open_drive);
+      // process junctions
+/*
+      for(OpenDRIVE::junction_iterator junction_it(open_drive->junction().begin());junction_it!=open_drive->junction().end();++junction_it)
+      {
+        for(junction::connection_iterator connection_it(junction_it->connection().begin()); connection_it!=junction_it->connection().end();++connection_it)
+        {
+          std::string incoming_road_id;
+          std::string connecting_road_id;
+          std::string contact_point;
+          if(connection_it->incomingRoad().present())
+            incoming_road_id=connection_it->incomingRoad().get();
+          else
+            throw CException(_HERE_,"Connectivity information missing");
+          if(connection_it->connectingRoad().present())
+            connecting_road_id=connection_it->connectingRoad().get();
+          else
+            throw CException(_HERE_,"Connectivity information missing");
+          if(connection_it->contactPoint().present())
+            contact_point=connection_it->contactPoint().get();
+          else
+            throw CException(_HERE_,"Connectivity information missing");
+          for(connection::laneLink_iterator lane_link_it(connection_it->laneLink().begin()); lane_link_it!=connection_it->laneLink().end();++lane_link_it)
+          {
+            int from_lane_id;
+            int to_lane_id;
+            if(lane_link_it->from().present())
+              from_lane_id=lane_link_it->from().get();
+            else
+              throw CException(_HERE_,"Connectivity information missing");
+            if(lane_link_it->to().present())
+              to_lane_id=lane_link_it->to().get();
+            else
+              throw CException(_HERE_,"Connectivity information missing");
+            // search the road segment starting at incoming_road_id and ending at connecting_road_id
+            std::string road_id=this->get_junction_road_id(*open_drive,incoming_road_id,connecting_road_id);
+            if(!road_id.empty())
+            {
+              COpendriveRoadSegment &prev_road=(*this)[incoming_road_id];
+              COpendriveRoadSegment &road=(*this)[road_id];
+              COpendriveRoadSegment &next_road=(*this)[connecting_road_id];
+              prev_road.link_segment(road,from_lane_id,-1);
+              road.link_segment(next_road,-1,to_lane_id);
+            }
+          }
+        }
+      }
+          */
     }catch (const xml_schema::exception& e){
       std::ostringstream os;
       os << e;
@@ -154,7 +281,7 @@ std::ostream& operator<<(std::ostream& out, COpendriveRoad &road)
   out << "Scale factor: " << road.scale_factor << std::endl;
   out << "Minimum road lenght: " << road.min_road_length << std::endl;
   for(unsigned int i=0;i<road.segments.size();i++)
-    std::cout << *road.segments[i] << std::endl;
+    std::cout << *road.segments[i];
 
   return out;
 }
diff --git a/src/opendrive_road_node.cpp b/src/opendrive_road_node.cpp
index 61c05b4..33a70c5 100644
--- a/src/opendrive_road_node.cpp
+++ b/src/opendrive_road_node.cpp
@@ -10,6 +10,7 @@ COpendriveRoadNode::COpendriveRoadNode()
   this->start_point.heading=0.0;
   this->lane=NULL;
   this->geometry=NULL;
+  this->index=-1;
 }
 
 COpendriveRoadNode::COpendriveRoadNode(const COpendriveRoadNode &object)
@@ -29,6 +30,7 @@ COpendriveRoadNode::COpendriveRoadNode(const COpendriveRoadNode &object)
     new_link=new COpendriveLink(*object.links[i]);
     this->links.push_back(new_link);
   }
+  this->index=object.index;
 }
 
 void COpendriveRoadNode::add_link(COpendriveRoadNode *node,opendrive_mark_t mark)
@@ -72,6 +74,11 @@ void COpendriveRoadNode::set_scale_factor(double scale)
     this->links[i]->set_scale_factor(scale);
 }
 
+void COpendriveRoadNode::set_index(unsigned int index)
+{
+  this->index=index;
+}
+
 void COpendriveRoadNode::load(const planView::geometry_type &geom_info,COpendriveLane *lane)
 {
   TOpendriveTrackPoint track_point;
@@ -123,6 +130,11 @@ double COpendriveRoadNode::get_scale_factor(void) const
   return this->scale_factor;
 }
 
+unsigned int COpendriveRoadNode::get_index(void) const
+{
+  return this->index;
+}
+
 TOpendriveWorldPoint COpendriveRoadNode::get_start_pose(void) const
 {
   return this->start_point;
@@ -173,22 +185,28 @@ void COpendriveRoadNode::operator=(const COpendriveRoadNode &object)
     new_link=new COpendriveLink(*object.links[i]);
     this->links.push_back(new_link);
   }
+  this->index=object.index;
 }
 
 std::ostream& operator<<(std::ostream& out, COpendriveRoadNode &node)
 {
+  out << "    Node " << node.index << ":" << std::endl;
+  out << "      parent lane: " << node.lane->get_id() << std::endl;
   out << "      start point: x: " << node.start_point.x << " y: " << node.start_point.y << " heading: " << node.start_point.heading << std::endl;
   if(node.lane!=NULL)
     out << "      lane id: " << node.lane->get_id() << std::endl;
   else
     out << "      Does not belong to a lane." << std::endl;
   if(node.geometry!=NULL)
-    out << *node.geometry << std::endl;
+    out << *node.geometry;
   else
     out << "      Does not have any associated geometry." << std::endl;
   out << "      Number of links: " << node.links.size() << std::endl;
   for(unsigned int i=0;i<node.links.size();i++)
-    out << *node.links[i] << std::endl;
+  {
+    out << "      Link " << i << ":" << std::endl;
+    out << *node.links[i];
+  }
   return out;
 }
 
diff --git a/src/opendrive_road_segment.cpp b/src/opendrive_road_segment.cpp
index 1b77e8e..c021614 100644
--- a/src/opendrive_road_segment.cpp
+++ b/src/opendrive_road_segment.cpp
@@ -57,7 +57,7 @@ COpendriveRoadSegment::COpendriveRoadSegment(const COpendriveRoadSegment &object
 
 void COpendriveRoadSegment::free(void)
 {
-  for(unsigned int i=-this->num_right_lanes;i<=this->num_left_lanes && i!=0;i++)
+  for(int i=-this->num_right_lanes;i<=this->num_left_lanes && i!=0;i++)
   {
     delete this->lanes[i];
     this->lanes[i]=NULL;
@@ -170,7 +170,7 @@ void COpendriveRoadSegment::add_nodes(OpenDRIVE::road_type &road_info)
     for(geom_it=road_info.planView().geometry().begin(); geom_it!=road_info.planView().geometry().end(); ++geom_it)
     {
       lane_offset=0.0;
-      for(unsigned int i=-1;i>=-this->num_right_lanes;i--)
+      for(int i=-1;i>=-this->num_right_lanes;i--)
       {
         new_node=new COpendriveRoadNode();
         new_node->set_resolution(this->resolution);
@@ -188,7 +188,7 @@ void COpendriveRoadSegment::add_nodes(OpenDRIVE::road_type &road_info)
     {
       geom_it--;
       lane_offset=0.0;
-      for(unsigned int i=1;i<=this->num_left_lanes;i++)
+      for(int i=1;i<=this->num_left_lanes;i++)
       {
         new_node=new COpendriveRoadNode();
         new_node->set_resolution(this->resolution);
@@ -210,7 +210,7 @@ void COpendriveRoadSegment::add_nodes(OpenDRIVE::road_type &road_info)
   }
 }
 
-void COpendriveRoadSegment::link_lanes(lanes::laneSection_type &lane_section)
+void COpendriveRoadSegment::link_neightbour_lanes(lanes::laneSection_type &lane_section)
 {
   opendrive_mark_t center_mark;
   center::lane_type center_lane;
@@ -218,66 +218,107 @@ void COpendriveRoadSegment::link_lanes(lanes::laneSection_type &lane_section)
   if(lane_section.center().lane().present())
   {
     center_lane=lane_section.center().lane().get();
-    if(center_lane.roadMark().begin()->type().present())
+    if(center_lane.roadMark().size()>1)
+      throw CException(_HERE_,"Only one road mark supported for lane");
+    else if(center_lane.roadMark().size()==0)
+      center_mark=OD_MARK_NONE;
+    else if(center_lane.roadMark().size()==1)
     {
-      if(center_lane.roadMark().begin()->type().get()=="none")
-        center_mark=OD_MARK_NONE;
-      else if(center_lane.roadMark().begin()->type().get()=="solid")
-        center_mark=OD_MARK_SOLID;
-      else if(center_lane.roadMark().begin()->type().get()=="broken")
-        center_mark=OD_MARK_BROKEN;
-      else if(center_lane.roadMark().begin()->type().get()=="solid_solid")
-        center_mark=OD_MARK_SOLID_SOLID;
-      else if(center_lane.roadMark().begin()->type().get()=="solid_broken")
-        center_mark=OD_MARK_SOLID_BROKEN;
-      else if(center_lane.roadMark().begin()->type().get()=="broken_solid")
-        center_mark=OD_MARK_BROKEN_SOLID;
-      else if(center_lane.roadMark().begin()->type().get()=="broken_broken")
-        center_mark=OD_MARK_BROKEN_BROKEN;
+      if(center_lane.roadMark().begin()->type1().present())
+      {
+        if(center_lane.roadMark().begin()->type1().get()=="none")
+          center_mark=OD_MARK_NONE;
+        else if(center_lane.roadMark().begin()->type1().get()=="solid")
+          center_mark=OD_MARK_SOLID;
+        else if(center_lane.roadMark().begin()->type1().get()=="broken")
+          center_mark=OD_MARK_BROKEN;
+        else if(center_lane.roadMark().begin()->type1().get()=="solid_solid")
+          center_mark=OD_MARK_SOLID_SOLID;
+        else if(center_lane.roadMark().begin()->type1().get()=="solid_broken")
+          center_mark=OD_MARK_SOLID_BROKEN;
+        else if(center_lane.roadMark().begin()->type1().get()=="broken_solid")
+         center_mark=OD_MARK_BROKEN_SOLID;
+        else if(center_lane.roadMark().begin()->type1().get()=="broken_broken")
+          center_mark=OD_MARK_BROKEN_BROKEN;
+        else
+          center_mark=OD_MARK_NONE;
+      }
       else
         center_mark=OD_MARK_NONE;
     }
+  }
+  for(int i=-this->num_right_lanes;i<0;i++)
+  {
+    if(this->lanes.find(i+1)!=this->lanes.end())// if the lane exists 
+      this->lanes[i]->link_neightbour_lane(this->lanes[i+1]);
     else
-      center_mark=OD_MARK_NONE;
+      this->lanes[i]->left_mark=OD_MARK_NONE;
   }
-  for(unsigned int i=-this->num_right_lanes;i<0;i++)
+  for(int i=this->num_left_lanes;i>0;i--)
+  {
+    if(this->lanes.find(i-1)!=this->lanes.end())// if the lane exists 
+      this->lanes[i]->link_neightbour_lane(this->lanes[i-1]);
+    else
+      this->lanes[i]->right_mark=OD_MARK_NONE;
+  }
+  if(this->lanes.find(1)!=this->lanes.end() && this->lanes.find(-1)!=this->lanes.end())
+  {
+    this->lanes[-1]->left_mark=center_mark;
+    this->lanes[1]->right_mark=center_mark;
+    this->lanes[-1]->link_neightbour_lane(this->lanes[1]);
+  }
+}
+
+void COpendriveRoadSegment::link_segment(COpendriveRoadSegment &segment)
+{
+  for(unsigned int i=0;i<this->next.size();i++)
+    if(this->next[i]->get_id()==segment.get_id())// the segment is already included
+      return;
+  this->next.push_back(&segment);
+  // link lanes
+  for(int i=-this->num_right_lanes;i<0;i++)
   {
-    if(i==-this->num_right_lanes)// right most lane
+    for(int j=i-1;j<=i+1;j++)
     {
-      if((i+1)==0)//center lane
+      if(segment.lanes.find(j)!=segment.lanes.end())
       {
-        if(this->lanes.find(i+2)!=this->lanes.end())
-          this->lanes[i]->link_left_lane(this->lanes[i+2]);
-        this->lanes[i]->left_mark=center_mark;
-      }
-      else
-      {
-        if(this->lanes.find(i+1)!=this->lanes.end())
-          this->lanes[i]->link_left_lane(this->lanes[i+1]);
-        this->lanes[i]->left_mark=this->lanes[i+1]->right_mark;
+        if(j==i-1)
+          this->lanes[i]->link_lane(segment.lanes[j],this->lanes[i]->right_mark);
+        else if(j==i)
+          this->lanes[i]->link_lane(segment.lanes[j],OD_MARK_NONE);
+        else
+          this->lanes[i]->link_lane(segment.lanes[j],this->lanes[i]->left_mark);
       }
     }
   }
-  for(unsigned int i=this->num_left_lanes;i>0;i--)
+  for(int i=1;i<=segment.num_left_lanes;i++)
   {
-    if(i==this->num_left_lanes)// right most lane
+    for(int j=i-1;j<=i+1;j++)
     {
-      if((i-1)==0)//center lane
-      {
-        if(this->lanes.find(i-2)!=this->lanes.end())
-          this->lanes[i]->link_right_lane(this->lanes[i-2]);
-        this->lanes[i]->right_mark=center_mark;
-      }
-      else
+      if(this->lanes.find(j)!=this->lanes.end())
       {
-        if(this->lanes.find(i-1)!=this->lanes.end())
-          this->lanes[i]->link_left_lane(this->lanes[i-1]);
-        this->lanes[i]->right_mark=this->lanes[i+1]->left_mark;
+        if(j==i-1)
+          segment.lanes[i]->link_lane(this->lanes[j],segment.lanes[i]->right_mark);
+        else if(j==i)
+          segment.lanes[i]->link_lane(this->lanes[j],OD_MARK_NONE);
+        else
+          segment.lanes[i]->link_lane(this->lanes[j],segment.lanes[i]->left_mark);
       }
     }
   }
 }
 
+void COpendriveRoadSegment::link_segment(COpendriveRoadSegment &segment,int from, int to)
+{
+  for(unsigned int i=0;i<this->next.size();i++)
+    if(this->next[i]->get_id()==segment.get_id())// the segment is already included
+      return;
+  this->next.push_back(&segment);
+  // link lanes
+  if(this->lanes.find(from)!=this->lanes.end() && segment.lanes.find(to)!=segment.lanes.end())
+    this->lanes[from]->link_lane(segment.lanes[to],OD_MARK_NONE);
+}
+
 void COpendriveRoadSegment::load(OpenDRIVE::road_type &road_info)
 {
   std::map<int,COpendriveLane *>::const_iterator lane_it;
@@ -303,7 +344,7 @@ void COpendriveRoadSegment::load(OpenDRIVE::road_type &road_info)
   // add road nodes
   this->add_nodes(road_info);
   // link lanes
-  this->link_lanes(*lane_section);
+  this->link_neightbour_lanes(*lane_section);
   // add road signals
   if(road_info.signals().present())
   {
@@ -448,7 +489,7 @@ void COpendriveRoadSegment::operator=(const COpendriveRoadSegment &object)
 
 std::ostream& operator<<(std::ostream& out, COpendriveRoadSegment &segment)
 {
-  out << "Road " << segment.get_name() << std::endl;
+  out << "Road " << segment.get_name() << " (" << segment.get_id() << ")" << std::endl;
   out << "  Previous road segments: " << segment.prev.size() << std::endl;
   for(unsigned int i=0;i<segment.prev.size();i++)
     out << "    " << segment.prev[i]->get_name() << std::endl;
@@ -456,17 +497,17 @@ std::ostream& operator<<(std::ostream& out, COpendriveRoadSegment &segment)
   for(unsigned int i=0;i<segment.next.size();i++)
     out << "    " << segment.next[i]->get_name() << std::endl;
   out << "  Number of right lanes: " << segment.num_right_lanes << std::endl;
-  for(unsigned int i=-1;i>=-segment.num_right_lanes;i--)
-    out << *segment.lanes[i] << std::endl;
+  for(int i=-1;i>=-segment.num_right_lanes;i--)
+    out << *segment.lanes[i];
   out << "  Number of left lanes: " << segment.num_left_lanes << std::endl;
-  for(unsigned int i=1;i<=segment.num_left_lanes;i++)
-    out << *segment.lanes[i] << std::endl;
+  for(int i=1;i<=segment.num_left_lanes;i++)
+    out << *segment.lanes[i];
   out << "  Number of signals: " << segment.signals.size() << std::endl;
   for(unsigned int i=0;i<segment.signals.size();i++)
-    std::cout << *segment.signals[i] << std::endl;
+    std::cout << *segment.signals[i];
   out << "  Number of objects: " << segment.objects.size() << std::endl;
   for(unsigned int i=0;i<segment.objects.size();i++)
-    std::cout << *segment.objects[i] << std::endl;
+    std::cout << *segment.objects[i];
 
   return out;
 }
-- 
GitLab