Main Content

Build Test Track 3D Scene in RoadRunner Using RoadRunner HD Map

This example shows how to build a RoadRunner scene for a test track using MATLAB® functions. You can build a scene of the test track using a Keyhole Markup Language (KML) file containing its latitude-longitude coordinates and a GeoTIFF file containing its elevation. To import the data files for the road, you must have a Mapping Toolbox™ license.

Import KML File for Test Track

In this example, you import the coordinates for the track centers into MATLAB from a KML file (Map data © 2022 by Google), and then view the coordinates by using MATLAB functions to plot the data imported from the KML file.

Create a geospatial table by reading geographic data from the KML file.

kmlData = readgeotable("TestTrackKMLData.kml");

Plot the coordinates of the test track.

geobasemap topographic

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

Import GeoTIFF File for Test Track

The sample terrain data used in this example has been downloaded from EarthExplorer, which provides earth science data from the archives of the United States Geological Survey (USGS). You can download the TIF file from the USGS website by uploading the shapefile to EarthExplorer, which crops EarthExplorer to the area of the test track.

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

T = geotable2table(kmlData,["Latitude","Longitude"]);
[georefGrid,spatialRef] = readgeoraster("TestTrack.tif",OutputType="double");
[lat1,lon1] = polyjoin(T.Latitude(1),T.Longitude(1));
[lat2,lon2] = polyjoin(T.Latitude(2),T.Longitude(2));
[lat3,lon3] = polyjoin(T.Latitude(3),T.Longitude(3));
[lat4,lon4] = polyjoin(T.Latitude(4),T.Longitude(4));
[lat5,lon5] = polyjoin(T.Latitude(5),T.Longitude(5));
[lat6,lon6] = polyjoin(T.Latitude(6),T.Longitude(6));
[lat7,lon7] = polyjoin(T.Latitude(7),T.Longitude(7));

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

ctrElev1 = geointerp(georefGrid,spatialRef,lat1,lon1);
ctrElev2 = geointerp(georefGrid,spatialRef,lat2,lon2);
ctrElev3 = geointerp(georefGrid,spatialRef,lat3,lon3);
ctrElev4 = geointerp(georefGrid,spatialRef,lat4,lon4);
ctrElev5 = geointerp(georefGrid,spatialRef,lat5,lon5);
ctrElev6 = geointerp(georefGrid,spatialRef,lat6,lon6);
ctrElev7 = geointerp(georefGrid,spatialRef,lat7,lon7);

Create RoadRunner HD Map

Create the RoadRunner HD Map and set the geographic reference for the region of interest.

Create an empty RoadRunner HD Map as a roadrunnerHDMap (RoadRunner) object.

rrMap = roadrunnerHDMap;

Compute the geographic coordinates of the road network origin as the center of the bounding quadrangle of the road network.

[latLim1,lonLim1] = geoquadline(lat1,lon1);
latMean1 = mean(latLim1);
lonMean1 = mean(lonLim1);

Set the geographic reference for the region of interest.

rrMap.GeoReference = [latMean1 lonMean1];

Project Latitude-Longitude Coordinates to xy Map Coordinates

Transform the imported latitude and longitude coordinates to xy map coordinates using a projected coordinate reference system (CRS). Then, using the xy map coordinates for the centers of the track, set the track width.

Read the Transverse Mercator projected CRS from the RoadRunner HD Map.

p = readCRS(rrMap);

Project the latitude and longitude coordinates to xy-coordinates.

[x1,y1] = projfwd(p,lat1,lon1);
[x2,y2] = projfwd(p,lat2,lon2);
[x3,y3] = projfwd(p,lat3,lon3);
[x4,y4] = projfwd(p,lat4,lon4);
[x5,y5] = projfwd(p,lat5,lon5);
[x6,y6] = projfwd(p,lat6,lon6);
[x7,y7] = projfwd(p,lat7,lon7);

Define the road centers and road widths of the test track.

rdCtrs1 = [x1 y1 ctrElev1];
rdWidth1 = 6.5;
rdCtrs2 = [x2 y2 ctrElev2];
rdWidth2 = 10;
rdCtrs3 = [x3 y3 ctrElev3];
rdWidth3 = 5;
rdCtrs4 = [x4 y4 ctrElev4];
rdWidth4 = 3.5;

Upsample Road Data

Because the data points obtained from the KML file are sparse, and the test track contains sharp curves, you must upsample the data to avoid modeling inaccurate track lanes. Upsample the data by using the helperRoadDimensions helper function.

[lftBndry1,rgtBndry1,ctrBndry1] = helperRoadDimensions(rdCtrs1,rdWidth1);
[lftBndry2,rgtBndry2,ctrBndry2] = helperRoadDimensions(rdCtrs2,rdWidth2);
[lftBndry3,rgtBndry3,ctrBndry3] = helperRoadDimensions(rdCtrs3,rdWidth3);
[lftBndry4,rgtBndry4,ctrBndry4] = helperRoadDimensions(rdCtrs4,rdWidth4);

Specify Lanes and Lane Boundaries

Create the RoadRunner HD Map using the interpolated data, and modify the data to resemble the test track.

Specify the lane properties for the RoadRunner HD Map.

rrMap.Lanes(4,1) = roadrunner.hdmap.Lane;
for i = 1:4
    rrMap.Lanes(i).Geometry = eval(strcat("ctrBndry",num2str(i)));
    rrMap.Lanes(i).TravelDirection = "Bidirectional";
    rrMap.Lanes(i).ID = strcat("Lane",num2str(i));
    rrMap.Lanes(i).LaneType = "Driving";

Specify the lane boundary information.

rrMap.LaneBoundaries(8,1) = roadrunner.hdmap.LaneBoundary;
for i = 1:4
    rrMap.LaneBoundaries(i*2-1).ID = strcat("Left",num2str(i));
    rrMap.LaneBoundaries(i*2).ID = strcat("Right",num2str(i));
    rrMap.LaneBoundaries(i*2-1).Geometry = eval(strcat('lftBndry',num2str(i)));
    rrMap.LaneBoundaries(i*2).Geometry = eval(strcat('rgtBndry',num2str(i)));

Specify the alignments between the lanes and lane boundaries.


Specify Lane Markings

Define file paths to the solid white and dashed white lane marking assets using roadrunner.hdmap.RelativeAssetPath (RoadRunner) objects.

wideSolidWhiteAsset = roadrunner.hdmap.RelativeAssetPath(AssetPath="Assets/Markings/Germany/WideSolidSingle.rrlms");
dashedWhiteAsset = roadrunner.hdmap.RelativeAssetPath(AssetPath="Assets/Markings/Germany/DashedSingle12.rrlms");

Create references for the wide solid white and dashed white markings using roadrunner.hdmap.MarkingReference (RoadRunner) objects, for applying the markings to the lane boundaries.

markingRefSW = roadrunner.hdmap.MarkingReference(MarkingID=roadrunner.hdmap.Reference(ID="WideSolidWhite"));
markingRefDW = roadrunner.hdmap.MarkingReference(MarkingID=roadrunner.hdmap.Reference(ID="DashedWhite"));

Create lane markings using a roadrunner.hdmap.LaneMarking (RoadRunner) object.

rrMap.LaneMarkings(2,1) = roadrunner.hdmap.LaneMarking;
rrMap.LaneMarkings(1).ID = "WideSolidWhite";
rrMap.LaneMarkings(2).ID = "DashedWhite";
rrMap.LaneMarkings(1).AssetPath = wideSolidWhiteAsset;
rrMap.LaneMarkings(2).AssetPath = dashedWhiteAsset;

Create the parameteric attributions using the marking references and the customized marking spans.

prmAttr1Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0 0.007],MarkingReference=markingRefSW);
prmAttr1Span2 = roadrunner.hdmap.ParametricAttribution(Span=[0.007 0.01],MarkingReference=markingRefDW);
prmAttr1Span3 = roadrunner.hdmap.ParametricAttribution(Span=[0.01 0.93],MarkingReference=markingRefSW);
prmAttr1Span4 = roadrunner.hdmap.ParametricAttribution(Span=[0.93 0.95],MarkingReference=markingRefDW);
prmAttr1Span5 = roadrunner.hdmap.ParametricAttribution(Span=[0.95 1],MarkingReference=markingRefSW);
prmAttr2Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0 0.575],MarkingReference=markingRefSW);
prmAttr2Span2 = roadrunner.hdmap.ParametricAttribution(Span=[0.575 0.602],MarkingReference=markingRefDW);
prmAttr2Span3 = roadrunner.hdmap.ParametricAttribution(Span=[0.602 1],MarkingReference=markingRefSW);
prmAttr3Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0 1],MarkingReference=markingRefSW);
prmAttr4Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0 0.439],MarkingReference=markingRefSW);
prmAttr4Span2 = roadrunner.hdmap.ParametricAttribution(Span=[0.471 0.655],MarkingReference=markingRefSW);
prmAttr4Span3 = roadrunner.hdmap.ParametricAttribution(Span=[0.684 1],MarkingReference=markingRefSW);
prmAttr5Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0.06 0.315],MarkingReference=markingRefSW);
prmAttr5Span2 = roadrunner.hdmap.ParametricAttribution(Span=[0.73 0.94],MarkingReference=markingRefSW);
prmAttr6Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0.1 0.85],MarkingReference=markingRefSW);
prmAttr7Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0 1],MarkingReference=markingRefSW);
prmAttr8Span1 = roadrunner.hdmap.ParametricAttribution(Span=[0.2 0.959],MarkingReference=markingRefSW);

Specify the parameteric attributes for the lane boundaries so that they resemble the test track.

rrMap.LaneBoundaries(1).ParametricAttributes = [prmAttr1Span1 prmAttr1Span2 prmAttr1Span3 prmAttr1Span4 prmAttr1Span5];
rrMap.LaneBoundaries(2).ParametricAttributes = [prmAttr2Span1 prmAttr2Span2 prmAttr2Span3];
rrMap.LaneBoundaries(3).ParametricAttributes = prmAttr3Span1;
rrMap.LaneBoundaries(4).ParametricAttributes = [prmAttr4Span1 prmAttr4Span2 prmAttr4Span3];
rrMap.LaneBoundaries(5).ParametricAttributes = [prmAttr5Span1 prmAttr5Span2];
rrMap.LaneBoundaries(6).ParametricAttributes = prmAttr6Span1;
rrMap.LaneBoundaries(7).ParametricAttributes = prmAttr7Span1;
rrMap.LaneBoundaries(8).ParametricAttributes = prmAttr8Span1;

Specify Barriers

Create a reference for the BridgeRailing asset, for applying the barriers to the lane boundaries.

path = roadrunner.hdmap.RelativeAssetPath(AssetPath="Assets/Extrusions/BridgeRailing.rrext");
rrMap.BarrierTypes(1) = roadrunner.hdmap.BarrierType(ID="BridgeRailing",ExtrusionPath=path);
guardRailRef = roadrunner.hdmap.Reference(ID="BridgeRailing");

Create barriers using a roadrunner.hdmap.Barrier (RoadRunner) object, and specify the barriers and their respective geometries.

rrMap.Barriers(5,1) = roadrunner.hdmap.Barrier;
for i = 1:5
    rrMap.Barriers(i).BarrierTypeReference = guardRailRef;
    rrMap.Barriers(i).ID = strcat('Barrier',num2str(i));
    rrMap.Barriers(i).FlipLaterally = false;
rrMap.Barriers(1).Geometry = lftBndry1(6:428,:);
rrMap.Barriers(2).Geometry = [x5 y5 ctrElev5];
rrMap.Barriers(3).Geometry = [x6 y6 ctrElev6];
rrMap.Barriers(4).Geometry = [x7 y7 ctrElev7];
rrMap.Barriers(5).Geometry = lftBndry4;

Set Geographic Boundaries and Write Map Data to Binary File

Setting the geographic boundaries for the RoadRunner HD Map centers the scene on the imported road and enables you to insert the road network 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 left boundary.

minBndry = min(lftBndry1);
maxBndry = max(lftBndry1);
rrMap.GeographicBoundary = [minBndry; maxBndry];

Plot the lane centers and lane boundaries.

title("RoadRunner HD Map of Test Track")
xlabel('x (m)')
ylabel('y (m)')

Figure contains an axes object. The axes object with title RoadRunner HD Map of Test Track, xlabel x (m), ylabel y (m) contains 2 objects of type line. These objects represent Lane Boundaries, Lane Centers.

Write the RoadRunner HD Map to a binary file using the write function, and copy the file to the assets folder for your project. This code uses a sample Windows® project path.

fileName1 = "TestTrackMap.rrhd";
copyfile TestTrackMap.rrhd C:\RR\MyProjects\Assets\

Import RoadRunner HD Map File into RoadRunner

Import your RoadRunner HD Map file into RoadRunner to build a scene, and then save the scene.

To open RoadRunner using MATLAB, specify the path to your project. This code shows a sample project folder in Windows. Open RoadRunner using the specified path to your project.

rrProjectPath = "C:\RR\MyProjects";
rrApp = roadrunner(rrProjectPath);

Import your RoadRunner HD Map file into RoadRunner and build the scene. To build the scene, you must have an active RoadRunner Scene Builder license.

options = roadrunnerHDMapImportOptions(ImportStep="Load");
importScene(rrApp,fullfile("C:\RR\MyProjects\Assets\","TestTrackMap.rrhd"),"RoadRunner HD Map",options)
buildScene(rrApp,"RoadRunner HD Map")

Save the built scene.

fileName2 = "TestTrackMap.rrscene";

This image shows the 3D scene of the test track scene in RoadRunner.

Test track scene in RoadRunner

To visualize the terrain surface, you can import the TestTrack.tif file into RoadRunner using the Elevation Map Tool (RoadRunner).

Test Track with terrain in RoadRunner

See Also


Related Topics