diff --git a/imap/lib/convertor.py b/imap/lib/convertor.py index e69a630..db26bfc 100644 --- a/imap/lib/convertor.py +++ b/imap/lib/convertor.py @@ -533,7 +533,7 @@ def _construct_signal_stopline(self, last_section_lanes, pb_signal): point = pb_segment.line_segment.point.add() point.CopyFrom(right_segment.point[-index]) - def convert_signal(self, xodr_road, pb_last_section): + def convert_signals(self, xodr_road, pb_last_section): for signal_reference in xodr_road.signals.signal_references: # todo(zero): need implement pass @@ -550,6 +550,11 @@ def convert_signal(self, xodr_road, pb_last_section): for pb_lane in pb_last_section: self.construct_signal_overlap(pb_lane, pb_signal) + def convert_objects(self): + # xodr_road.reference_line + # pb_parking_space = self.pb_map.parking_space.add() + pass + def convert_roads(self): for _, xodr_road in self.xodr_map.roads.items(): pb_road = self.pb_map.road.add() @@ -561,19 +566,25 @@ def convert_roads(self): if xodr_road.road_type.road_type is None: pb_road.type = map_road_pb2.Road.CITY_ROAD + # Generate reference line, Note that most objects rely on reference_line!!! xodr_road.generate_reference_line() xodr_road.add_offset_to_reference_line() xodr_road.add_origin_to_reference_line( self.origin_x, self.origin_y) - # Todo(zero): + draw_line(xodr_road.reference_line, 'r', reference_line=True, label="reference line " + str(pb_road.id.id)) + # Generate Lanes xodr_road.process_lanes() - pb_last_section = self.convert_lane(xodr_road, pb_road) + # Todo(zero): need to complete signal - self.convert_signal(xodr_road, pb_last_section) + # Generate Signals + self.convert_signals(xodr_road, pb_last_section) + + self.convert_objects(xodr_road) + def _is_valid_junction(self, xodr_junction): connecting_roads = set() diff --git a/imap/lib/opendrive/objects.py b/imap/lib/opendrive/objects.py new file mode 100644 index 0000000..ea2fb08 --- /dev/null +++ b/imap/lib/opendrive/objects.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python + +# Copyright 2021 daohu527 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import abc +from enum import Enum + + +class ObjectType(Enum): + BARRIER = "barrier" + BUILDING = "building" + CROSSWALK = "crosswalk" + GANTRY = "gantry" + OBSTACLE = "obstacle" + PARKING_SPACE = "parkingSpace" + POLE = "pole" + ROAD_MARK = "roadMark" + TRAFFIC_ISLAND = "trafficIsland" + TREE = "tree" + VEGETATION = "vegetation" + + +class Object(metaclass=abc.ABCMeta): + def parse_from(self, raw_object): + self.id = raw_object.attrib.get('id') + self.name = raw_object.attrib.get('name') + self.type = raw_object.attrib.get('type') + self.subtype = raw_object.attrib.get('subtype') + self.s = raw_object.attrib.get('s') + self.t = raw_object.attrib.get('t') + self.zOffset = raw_object.attrib.get('zOffset') + self.orientation = raw_object.attrib.get('orientation') + self.length = raw_object.attrib.get('length') + self.width = raw_object.attrib.get('width') + self.height = raw_object.attrib.get('height') + self.hdg = raw_object.attrib.get('hdg') + self.pitch = raw_object.attrib.get('pitch') + self.roll = raw_object.attrib.get('roll') + self.radius = raw_object.attrib.get('radius') + self.validLength = raw_object.attrib.get('validLength') + self.dynamic = raw_object.attrib.get('dynamic') + self.perpToRoad = raw_object.attrib.get('perpToRoad') + + +class Barrier(Object): + def __init__(self) -> None: + pass + + +class Building(Object): + def __init__(self) -> None: + pass + + +class Crosswalk(Object): + def __init__(self) -> None: + pass + + +class Gantry(Object): + def __init__(self) -> None: + pass + + +class Obstacle(Object): + def __init__(self) -> None: + pass + + +class ParkingSpace(Object): + def __init__(self) -> None: + pass + +class Pole(Object): + def __init__(self) -> None: + pass + + +class RoadMark(Object): + def __init__(self) -> None: + pass + + +class TrafficIsland(Object): + def __init__(self) -> None: + pass + + +class Tree(Object): + def __init__(self) -> None: + pass + + +class Vegetation(Object): + def __init__(self) -> None: + pass + + +class Objects: + def __init__(self) -> None: + self.objects = [] + + def parse_from(self, raw_objects): + for _, xodr_object in raw_objects.items(): + object_type = xodr_object.attrib.get('type') + if object_type == ObjectType.BARRIER: + obj = Barrier() + elif object_type == ObjectType.BUILDING: + obj = Building() + elif object_type == ObjectType.CROSSWALK: + obj = Crosswalk() + elif object_type == ObjectType.GANTRY: + obj = Gantry() + elif object_type == ObjectType.OBSTACLE: + obj = Obstacle() + elif object_type == ObjectType.PARKING_SPACE: + obj = ParkingSpace() + elif object_type == ObjectType.POLE: + obj = Pole() + elif object_type == ObjectType.ROAD_MARK: + obj = RoadMark() + elif object_type == ObjectType.TRAFFIC_ISLAND: + obj = TrafficIsland() + elif object_type == ObjectType.TREE: + obj = Tree() + elif object_type == ObjectType.VEGETATION: + obj = Vegetation() + else: + raise NotImplementedError(f"{object_type}") + + obj.parse_from(xodr_object) + self.objects.append(obj) diff --git a/imap/lib/opendrive/road.py b/imap/lib/opendrive/road.py index ef60a5b..6c7ae6b 100644 --- a/imap/lib/opendrive/road.py +++ b/imap/lib/opendrive/road.py @@ -21,6 +21,7 @@ from imap.lib.opendrive.profile import ElevationProfile, LateralProfile from imap.lib.opendrive.lanes import Lanes from imap.lib.opendrive.signals import Signals +from imap.lib.opendrive.objects import Objects GEOMETRY_SKIP_LENGTH = 0.01 @@ -44,9 +45,13 @@ def parse_from(self, raw_speed): class RoadType: - def __init__(self, s=None, road_type=None): + def __init__(self, s=None, road_type=None, country=None): + # required self.s = s self.road_type = road_type + # optional + self.country = country + self.speed = Speed() def parse_from(self, raw_road_type): @@ -104,13 +109,15 @@ def __init__(self, name=None, length=None, road_id=None, self.road_id = road_id self.junction_id = junction_id - self.link = Link() self.road_type = RoadType() + + self.link = Link() + self.lanes = Lanes() + self.objects = Objects() + self.signals = Signals() self.plan_view = PlanView() self.elevation_profile = ElevationProfile() self.lateral_profile = LateralProfile() - self.lanes = Lanes() - self.signals = Signals() # private self.reference_line = [] @@ -166,6 +173,10 @@ def parse_from(self, raw_road): raw_signals = raw_road.find('signals') self.signals.parse_from(raw_signals) + # objects + raw_objects = raw_road.find('objects') + self.objects.parse_from(raw_objects) + # post processing self.post_processing()