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.
geoplot(kmlData)
geobasemap topographic
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
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"; end
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))); end
Specify the alignments between the lanes and lane boundaries.
leftBoundary(rrMap.Lanes(1),"Left1",Alignment="Forward"); rightBoundary(rrMap.Lanes(1),"Right1",Alignment="Forward"); leftBoundary(rrMap.Lanes(2),"Left2",Alignment="Forward"); rightBoundary(rrMap.Lanes(2),"Right2",Alignment="Forward"); leftBoundary(rrMap.Lanes(3),"Left3",Alignment="Forward"); rightBoundary(rrMap.Lanes(3),"Right3",Alignment="Forward"); leftBoundary(rrMap.Lanes(4),"Left4",Alignment="Forward"); rightBoundary(rrMap.Lanes(4),"Right4",Alignment="Forward");
Specify Lane Markings
Define file paths to the solid white and dashed white lane marking assets using roadrunner.hdmap.RelativeAssetPath
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
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
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
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; end 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.
plot(rrMap) title("RoadRunner HD Map of Test Track") xlabel('x (m)') ylabel('y (m)')
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"; write(rrMap,fileName1) 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";
saveScene(rrApp,fileName2)
This image shows the 3D scene of the test track scene in RoadRunner.
To visualize the terrain surface, you can import the TestTrack.tif
file into RoadRunner using the Elevation Map Tool.