Main Content

Build Pikes Peak RoadRunner 3D Scene Using RoadRunner HD Map

This example shows how to build a RoadRunner 3D scene for Pikes Peak, Colorado, using MATLAB functions. You can build a scene for the full road, or a section of Pikes Peak Road using a Keyhole Markup Language (KML) file containing its latitude-longitude coordinates and a Geostationary Earth Orbit Tagged Image File Format (GeoTIFF) file containing its elevation. Use Mapping Toolbox® to import the data files for the road.

Import KML File for Pikes Peak

You can choose to build the RoadRunner HD Map for either a section of the road or the full road. Note that building a section of the road requires significantly less time than building the entire scene. In this example, you import the coordinates for the road centers into MATLAB from a KML file (Map data ©2022 Google), and then plot the data imported from the KML file to view the coordinates.

To build only a section of the road, specify buildFullRoad as false. To build the full road, specify it as true.

buildFullRoad = false; 

Read the data from the KML file.

if buildFullRoad
    kmlData = readgeotable("PikesPeakFullRoadData.kml"); %#ok<*UNRCH> 
else
    kmlData = readgeotable("PikesPeakRoadSectionData.kml");
end

Plot the coordinates of Pikes Peak road.

geoplot(kmlData)
geobasemap topographic

Figure contains an axes object. The axes object contains an object of type line.

Import GeoTIFF File for Pikes Peak Elevation

To include elevation for Pikes Peak Road, download terrain data for the area from the United States Geological Survey National Map Services, and query the elevations for the coordinates corresponding to the road. The data has been processed by cropping the USGS data to the Pikes Peak area.

United States Geological Survey National Map Services TNM Download

Convert the geospatial table to table of road centers to a obtain the latitude and longitude coordinates for the road.

T = geotable2table(kmlData,["Latitude","Longitude"]);
[lat,lon] = polyjoin(T.Latitude,T.Longitude);

Query the elevations of the road coordinates from the terrain data.

[georefGrid,spatialRef] = readgeoraster('PikesPeak.tif','OutputType','double');
ctrElev = geointerp(georefGrid,spatialRef,lat,lon);

Upsample Data

Because the data points obtained from the KML file are spare, and the road contains sharp curves, you must upsample the data to avoid modeling inaccurate road lanes. You can upsample the data by using helperRoadDimensions helper function. First, you must convert the imported latitude and longitude coordinates to xy-map coordinates. Then, using the converted coordinates for the centers of the road, you must set the road width. In this example, Pikes Peak Road is a two-lane road, so you can assume a total road width of 7.4 meters based on the average lane width of 3.7 meters.

Compute the georeference origin as the center of the bounding quadrangle.

[latlim,lonlim] = geoquadline(lat,lon);
lat0 = mean(latlim);
lon0 = mean(lonlim);

Create a Transverse Mercator projection, customized for the region of interest.

wkt = ['PROJCS["WGS 84 / Transverse Mercator",' ...
    'GEOGCS["WGS 84",' ...
    'DATUM["WGS_1984",' ...
    'SPHEROID["WGS 84",6378137,298.257223563]],' ...
    'PRIMEM["Greenwich",0],' ...
    'UNIT["degree",0.0174532925199433,' ...
    'AUTHORITY["EPSG","9122"]],' ...
    'AUTHORITY["EPSG","4326"]],' ...
    'PROJECTION["Transverse_Mercator"],' ...
    'PARAMETER["latitude_of_origin",' num2str(lat0,7) '],' ...
    'PARAMETER["central_meridian",' num2str(lon0,7) '],' ...
    'PARAMETER["scale_factor",0.9996],' ...
    'PARAMETER["false_easting",0],' ...
    'PARAMETER["false_northing",0],' ...
    'UNIT["metre",1],' ...
    'AXIS["Easting",EAST],' ...
    'AXIS["Northing",NORTH]]'];
p = projcrs(wkt);

Project the latitude and longitude coordinates to xy-coordinates.

[x,y] = projfwd(p,lat,lon);

Define the road centers and the road width.

rdCtrs = [x y ctrElev];
rdWidth = 7.4;

Upsample the data for the lane boundaries to obtain a better result for the road curves.

[lftBndry,rgtBndry,ctrBndry] = helperRoadDimensions(rdCtrs,rdWidth);

Create RoadRunner HD Map

Create the RoadRunner HD Map using the interpolated data, and modify the road to resemble Pikes Peak Road, which consists of two lanes and three lane boundaries. Then, apply a solid white marking to the outer lane boundaries and a double yellow marking between the two lanes for the entire length of the road.

Create an empty RoadRunner HD Map.

rrMap = roadrunnerHDMap;

To improve performance as the number of objects in the map increases, initialize the Lanes and LaneBoundaries properties of the HD Map.

rrMap.Lanes(2,1) = roadrunner.hdmap.Lane();
rrMap.LaneBoundaries(3,1) = roadrunner.hdmap.LaneBoundary();

Assign Lane property values. Use deal to match the input lists to the output lists.

[rrMap.Lanes.ID] = deal("Lane1","Lane2");
[rrMap.Lanes.TravelDirection] = deal("Backward","Forward");
[rrMap.Lanes.LaneType] = deal("Driving");

Average the coordinates of the left and right lane boundaries with the corresponding coordinates of the center lane boundary to obtain the lane centers.

lftLane = (lftBndry+ctrBndry)/2;
rgtLane = (rgtBndry+ctrBndry)/2;
[rrMap.Lanes.Geometry] = deal(lftLane,rgtLane);

Assign IDs and the corresponding coordinates to the three lane boundaries.

[rrMap.LaneBoundaries.ID] = deal("Left","Center","Right");
[rrMap.LaneBoundaries.Geometry] = deal(lftBndry,ctrBndry,rgtBndry);

Associate the lane boundaries to their lanes using their IDs. Note that both lanes share the center lane boundary.

leftBoundary(rrMap.Lanes(1),"Left",Alignment="Forward");
rightBoundary(rrMap.Lanes(1),"Center",Alignment="Forward");
leftBoundary(rrMap.Lanes(2),"Center",Alignment="Forward");
rightBoundary(rrMap.Lanes(2),"Right",Alignment="Forward");

Define the file path to the solid white lane marking asset.

solidWhiteAsset = roadrunner.hdmap.RelativeAssetPath(AssetPath="Assets/Markings/SolidSingleWhite.rrlms");

Define the path to the solid double yellow lane marking asset. Add both lane markings to the HD Map.

doubleYellowAsset = roadrunner.hdmap.RelativeAssetPath(AssetPath="Assets/Markings/SolidDoubleYellow.rrlms");
rrMap.LaneMarkings(2,1) = roadrunner.hdmap.LaneMarking();
[rrMap.LaneMarkings.ID] = deal("SolidWhite","DoubleYellow");
[rrMap.LaneMarkings.AssetPath] = deal(solidWhiteAsset,doubleYellowAsset);

Specify that the markings span the entire length of their lane boundary. Create a reference and attribution for the the solid double yellow marking.

markingSpan = [0 1];
markingRefSY = roadrunner.hdmap.MarkingReference(MarkingID=roadrunner.hdmap.Reference(ID="DoubleYellow"));
markingAttribSY = roadrunner.hdmap.ParametricAttribution(MarkingReference=markingRefSY,Span=markingSpan);

Create a reference and attribution for the solid white marking. Then, to apply the solid white marking to the left and right lane boundaries and the solid double yellow marking to the center lane boundary.

markingRefSW = roadrunner.hdmap.MarkingReference(MarkingID=roadrunner.hdmap.Reference(ID="SolidWhite"));
markingAttribSW = roadrunner.hdmap.ParametricAttribution(MarkingReference=markingRefSW,Span=markingSpan);
[rrMap.LaneBoundaries.ParametricAttributes] = deal(markingAttribSW,markingAttribSY,markingAttribSW);

Set Geographic Boundaries and Reference

Setting the geographic boundaries and reference for the RoadRunner HD Map centers the scene on the imported road and enables you to insert the road into the scene without using the World Settings Tool in RoadRunner.

Set the geographic bounds for the map as the minimum and maximum coordinate values of the center boundary.

geoBounds = [min(ctrBndry); max(ctrBndry)];
rrMap.GeographicBoundary = geoBounds;

Set the geographic reference for the region of interest.

rrMap.GeoReference = [lat0 lon0];

Plot the lane centers and lane boundaries.

plot(rrMap)
title('RoadRunner HD Map of Pikes Peak Road')
xlabel('x (m)')
ylabel('y (m)')

Figure contains an axes object. The axes object with title RoadRunner HD Map of Pikes Peak Road contains 2 objects of type line. These objects represent Lane Boundaries, Lane Centers.

Export RoadRunner HD Map and Import to RoadRunner

Save the RoadRunner HD Map to a file. Import it into RoadRunner by adding the file to a folder in the Library Browser and dragging it into the scene. For more information on importing an HD Map file into RoadRunner, see Import HD Map File into RoadRunner. Build the scene using the Scene Builder Tool.

Specify an output filename for based on the data used to construct the RoadRunner HD Map.

if buildFullRoad
    fileName = "PikesPeakFullRoad.rrhd";
else
    fileName = "PikesPeakRoadSection.rrhd";
end

Write the map to the file.

write(rrMap,fileName);

This figure shows a 3D scene of Pikes Peak Road built using RoadRunner Scene Builder.

PikesPeakExample.png

To visualize the terrain, you can import the PikesPeak.tif file into RoadRunner using the Elevation Map Tool.

PikesPeakExampleWithElevation.png

See Also

|

Related Topics