Skip to content

Commit

Permalink
cleaning up generators, adding deprecation warnings to old function (…
Browse files Browse the repository at this point in the history
…to be removed later), more tests, fixing so lanedef for right lane can use the 'sublane' input as positive as well as negative values, new example to replace old generator
  • Loading branch information
mander76 committed Dec 13, 2023
1 parent aa00002 commit f5580ae
Show file tree
Hide file tree
Showing 11 changed files with 794 additions and 233 deletions.
6 changes: 1 addition & 5 deletions docu/Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,8 @@ For most simple roads, the generators that are provided in the __xodr__ module c
The *create_road* function is very useful to create rather simple roads with either fixed amount of lanes or simple lane-merge/splits.
Some example usage of this can be seen in [highway_example](examples/xodr/highway_example.html).

#### create_cloth_arc_cloth
The *create_cloth_arc_cloth* function creates road with a smooth curve based on a clothoid + arc + clothoid. This is often used since the curvature of the road will change continiously (and resulting in nice steering wheel changes for a driver).

#### create_3cloths
Similarly to *create_cloth_arc_cloth*, the *create_3cloths* function creates a smooth curve based on 3 consecutive spiral geoemtries (using [pyclothoids](https://github.com/phillipd94/pyclothoids))

The *create_3cloths* function creates a smooth curve based on 3 consecutive spiral geoemtries (using [pyclothoids](https://github.com/phillipd94/pyclothoids))

#### LaneDef
LaneDef is a helper class that enables simple lane merge/split roads to be created. LaneDef can also be used to define different widths of lanes, aswell as lane widths changing. The LaneDefs definition can be used together with the create_road generator (see [highway_example_with_merge_and_split](examples/xodr/highway_example_with_merge_and_split.html), and [full_junction_with_LaneDef](examples/xodr/full_junction_with_LaneDef.html)).
Expand Down
82 changes: 82 additions & 0 deletions examples/xodr/clothoid_generation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""
scenariogeneration
https://github.com/pyoscx/scenariogeneration
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
Copyright (c) 2023 The scenariogeneration Authors.
Example how to utilze pyclothoids to create a road to match two points
Some features used:
- create_road
- pyclothoids* (external package)
"""


from scenariogeneration import xodr, prettyprint, ScenarioGenerator

import pyclothoids as pcloth
import os


class Scenario(ScenarioGenerator):
def __init__(self):
super().__init__()

def road(self, **kwargs):
start_x = 0 # x coordinate at the beginning of the curvature
start_y = 0 # y coordinate at the beginning of the curvature
start_h = 0 # heading at the beginning of the curvature

end_x = 150 # x coordinate at the end of the curvature
end_y = 20 # y coordinate at the end of the curvature
end_h = 0 # heading at the end of the curvature

clothoids = pcloth.SolveG2(
start_x,
start_y,
start_h,
xodr.STD_START_CLOTH,
end_x,
end_y,
end_h,
xodr.STD_START_CLOTH,
)
# create spirals from each responce
roadgeoms = [
xodr.Spiral(x.KappaStart, x.KappaEnd, length=x.length) for x in clothoids
]

# create the road
road = xodr.create_road(roadgeoms, id=0, left_lanes=2, right_lanes=2)

## Create the OpenDrive class (Master class)
odr = xodr.OpenDrive("myroad")

## Finally add roads to Opendrive
odr.add_road(road)

## Adjust initial positions of the roads looking at succ-pred logic
odr.adjust_roads_and_lanes()

return odr


if __name__ == "__main__":
sce = Scenario()
# Print the resulting xml
prettyprint(sce.road().get_element())

# write the OpenSCENARIO file as xosc using current script name
sce.generate(".")

# uncomment the following lines to display the scenario using esmini
# from scenariogeneration import esmini
# esmini(sce,os.path.join('esmini'))
52 changes: 17 additions & 35 deletions examples/xodr/full_junction.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,17 @@
Copyright (c) 2022 The scenariogeneration Authors.
An example, using the generators, showing how to create different types of junctions
NOTE: USE CommonJunctionCreator instead, this is old
An example, using the generators, showing how to create different symetric junctions,
the numintersections can be changed to create different junctions
All the roads in a junction are formed by clothoid-arc-clothoid geotrietries
In this example we can create a junction given
option1. the distance R of every road from the center of the junction - R can change for each road
option2. the radius of the inner arc geometry - for this case you can only use
numintersections = 3 or 4
angles = [0,np.pi/2, 3*np.pi/2] or [0, np.pi/2, np.pi, 3*np.pi/2]
Some features used:
- create_straight_road
- create_road
- create_junction_roads
- CommonJunctionCreator
- create_junction
"""

import numpy as np
Expand All @@ -40,10 +33,13 @@ def __init__(self):
def road(self, **kwargs):
roads = []
numintersections = 3
angles = []
nlanes = 1

# setup junction creator
junction_creator = xodr.CommonJunctionCreator(100, "my junction")

# create some roads
for i in range(numintersections):
# roads.append(xodr.create_straight_road(i,n_lanes=1))
roads.append(
xodr.create_road(
[xodr.Line(100)],
Expand All @@ -53,35 +49,21 @@ def road(self, **kwargs):
right_lanes=nlanes,
)
)
# use this instead to change the number of lanes in the crossing
# roads.append(xodr.generators.create_straight_road(i, length=100, junction=-1, n_lanes=5, lane_offset=3))
angles.append(i * 2 * np.pi / numintersections)

# use this for a T-crossing instead
# angles = [0, np.pi/2, 3*np.pi/2]

# use this non perpendicular crossing
angles = [0, 1.3 * np.pi / 2, 3.2 * np.pi / 2]

# option 1. uncomment this if you want to create the junction from the distance R of every road from the center of the junction
junction_roads = xodr.create_junction_roads(roads, angles, [20])
# option 2. creation of junction given the radius of the inner arc geometry
# junction_roads = xodr.create_junction_roads_from_arc(roads,angles,8)

# create the junction
junction = xodr.create_junction(junction_roads, 1, roads)
# add road to junciton
junction_creator.add_incoming_road_circular_geometry(
roads[i], 20, i * 2 * np.pi / numintersections, "successor"
)

# create the opendrive and add all roads and the junction
# add connection to all previous roads
for j in range(i):
junction_creator.add_connection(j, i)

odr = xodr.OpenDrive("myroad")

odr.add_junction(junction)

for r in roads:
odr.add_road(r)

for j in junction_roads:
odr.add_road(j)
odr.add_junction_creator(junction_creator)

odr.adjust_roads_and_lanes()

Expand Down
53 changes: 26 additions & 27 deletions examples/xodr/junction_with_signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,43 +26,42 @@ def __init__(self):
def road(self, **kwargs):
roads = []
incoming_roads = 4
angles = []
nlanes = 1
# setup junction creator
junction_creator = xodr.CommonJunctionCreator(100, "my junction")

# create roads and connections
for i in range(incoming_roads):
roads.append(xodr.create_straight_road(i))
# use this instead to change the number of lanes in the crossing
# roads.append(xodr.generators.create_straight_road(i, length=100, junction=-1, n_lanes=2, lane_offset=3))
angles.append(i * 2 * np.pi / incoming_roads)
if angles[-1] == 0:
roads[-1].add_signal(
xodr.Signal(s=98.0, t=-4, country="USA", Type="R1", subtype="1")
)
else:
roads[-1].add_signal(
xodr.Signal(
s=2.0,
t=4,
country="USA",
Type="R1",
subtype="1",
orientation=xodr.Orientation.negative,
)
roads.append(
xodr.create_road(
[xodr.Line(100)],
i,
center_road_mark=xodr.STD_ROADMARK_BROKEN,
left_lanes=nlanes,
right_lanes=nlanes,
)
)
roads[-1].add_signal(
xodr.Signal(s=98.0, t=-4, country="USA", Type="R1", subtype="1")
)

# use this for a T-crossing instead
# angles = [0,np.pi/2, 3*np.pi/2]
# add road to junciton
junction_creator.add_incoming_road_circular_geometry(
roads[i], 20, i * 2 * np.pi / incoming_roads, "successor"
)

# add connection to all previous roads
for j in range(i):
junction_creator.add_connection(j, i)

# print(roads)
junc = xodr.create_junction_roads(roads, angles, [8])
odr = xodr.OpenDrive("myroad")
junction = xodr.create_junction(junc, 1, roads)

odr.add_junction(junction)
for r in roads:
odr.add_road(r)
for j in junc:
odr.add_road(j)
odr.add_junction_creator(junction_creator)

odr.adjust_roads_and_lanes()

return odr


Expand Down
5 changes: 3 additions & 2 deletions scenariogeneration/xodr/elevation.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ def add_superelevation(self, superelevation):
"""
if not isinstance(superelevation, _Poly3Profile):
raise TypeError(
"add_elevation requires an _Elevation as input, not "
"add_elevation requires an _Poly3Profile as input, not "
+ str(type(superelevation))
)
self.superelevations.append(superelevation)
Expand All @@ -131,7 +131,8 @@ def add_shape(self, shape):
"""
if not isinstance(shape, _Poly3Profile):
raise TypeError(
"add_elevation requires an _Elevation as input, not " + str(type(shape))
"add_elevation requires an _Poly3Profile as input, not "
+ str(type(shape))
)
self.shapes.append(shape)
return self
Expand Down
42 changes: 36 additions & 6 deletions scenariogeneration/xodr/generators.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
RemovedFunctionality,
)

from warnings import warn


def std_roadmark_solid():
return RoadMark(RoadMarkType.solid, 0.2)
Expand Down Expand Up @@ -180,7 +182,7 @@ def create_lanes_merge_split(
# check if the number of lanes should change or not
if (
right_lane[ls].n_lanes_start > right_lane[ls].n_lanes_end
and i == -right_lane[ls].sub_lane - 1
and i == np.abs(right_lane[ls].sub_lane) - 1
):
# lane merge
coeff = get_coeffs_for_poly3(
Expand All @@ -193,7 +195,7 @@ def create_lanes_merge_split(
rightlane.add_roadmark(rm)
elif (
right_lane[ls].n_lanes_start < right_lane[ls].n_lanes_end
and i == -right_lane[ls].sub_lane - 1
and i == np.abs(right_lane[ls].sub_lane) - 1
):
# lane split
coeff = get_coeffs_for_poly3(
Expand Down Expand Up @@ -227,6 +229,7 @@ def create_lanes_merge_split(

lsec.add_right_lane(rightlane)

# do the left lanes
for i in range(max(left_lane[ls].n_lanes_start, left_lane[ls].n_lanes_end)):
# add broken roadmarks for all lanes, except for the outer lane where a solid line is added
if i == max(left_lane[ls].n_lanes_start, left_lane[ls].n_lanes_end) - 1:
Expand Down Expand Up @@ -462,6 +465,11 @@ def create_straight_road(road_id, length=100, junction=-1, n_lanes=1, lane_offse
-------
road (Road): a straight road
"""
warn(
"create_straight_road should not be used anymore, please use the create_road function instead",
DeprecationWarning,
2,
)
# create geometry
line1 = Line(length)

Expand Down Expand Up @@ -520,7 +528,11 @@ def create_cloth_arc_cloth(
-------
road (Road): a road built up of a Spiral-Arc-Spiral
"""

warn(
"create_cloth_arc_cloth should not be used anymore, please use the create_road (see exampels/xodr/clothoid_generation.py) function instead",
DeprecationWarning,
2,
)
pv = PlanView()
# adjust sign if angle is negative
if cloth_angle < 0 and arc_curv > 0:
Expand Down Expand Up @@ -605,7 +617,11 @@ def create_3cloths(
-------
road (Road): a road built up of a Spiral-Spiral-Spiral
"""

warn(
"create_cloth_arc_cloth should not be used anymore, please use the create_road (see exampels/xodr/clothoid_generation.py) function instead",
DeprecationWarning,
2,
)
pv = PlanView()

# create geometries
Expand Down Expand Up @@ -654,6 +670,7 @@ def get_lanes_offset(road1, road2, contactpoint):
lane_offset (int):
"""

# now we always look at lanesection[0] to take the number of lanes
# TO DO - understand if the roads are connect through end or start and then take the relative lane section
if contactpoint == ContactPoint.end:
Expand Down Expand Up @@ -722,6 +739,11 @@ def create_junction_roads_standalone(
junction_roads (list of Road): a list of all roads in a junction without connections added
"""
warn(
"create_junction_roads_standalone should not be used anymore, please use the CommonJunctionCreator function instead",
DeprecationWarning,
2,
)
angle = np.pi / 2
angle_cloth = angle * spiral_part
spiral_length = 2 * abs(angle_cloth * r)
Expand Down Expand Up @@ -813,7 +835,11 @@ def create_junction_roads_from_arc(
-------
junction_roads (list of Road): a list of all roads needed for all traffic connecting the roads
"""

warn(
"create_junction_roads_from_arc should not be used anymore, please use the CommonJunctionCreator function instead",
DeprecationWarning,
2,
)
# arc_part = 1 - 2*spiral_part
spiral_part = (1 - arc_part) / 2

Expand Down Expand Up @@ -935,7 +961,11 @@ def create_junction_roads(
-------
junction_roads (list of Road): a list of all roads needed for all traffic connecting the roads
"""

warn(
"create_junction_roads_from_arc should not be used anymore, please use the CommonJunctionCreator function instead",
DeprecationWarning,
2,
)
if len(roads) is not len(angles):
raise GeneralIssueInputArguments("roads and angles do not have the same size.")

Expand Down
Loading

0 comments on commit f5580ae

Please sign in to comment.