Challenge

Project 1

Project Objective:

  • To obtain real-time coordinates of any chosen place from Google Earth and save the location as a KML file.
  • To parse the KML file in MATLAB and extract the location co-ordinates (latitude, longitude).
  • To import roads from the location using the ‘OpenStreetMap’ web service into a driving scenario.
  • To plot the path taken by a vehicle following a pre-defined route with specified location co-ordinates (latitude, longitude) in the imported road network using m-scripting.

The real-time co-ordinates of MathWorks Campus located at ‘1 Apple Hill Dr, Natick, MA 01760, United States’ is obtained from Google Earth. The latitude and longitude of the location as seen in Google Earth is: 42.2996° and -71.3508° respectively.

Image: MathWorks -Apple Hill Campus as seen in Google Earth

Image: Latitude and Longitude of the location

The location is then exported as a KML file. Keyhole Markup Language (KML) is an XML notation for expressing geographic annotation and visualization within two-dimensional maps and three-dimensional Earth browsers. KML was developed for use with Google Earth, which was originally named Keyhole Earth Viewer. It was created by Keyhole, Inc, which was acquired by Google in 2004. KML became an international standard of the Open Geospatial Consortium in 2008. Google Earth was the first program able to view and graphically edit KML files, but other projects such as Marble have added KML support.

The KML file specifies a set of features (place marks, images, polygons, 3D models, textual descriptions, etc.) that can be displayed on maps in geospatial software implementing the KML encoding. Each place always has a longitude and a latitude. Other data can make the view more specific, such as tilt, heading, altitude, which together define a "camera view" along with a timestamp or timespan. KML shares some of the same structural grammar as Geography Markup Language (GML).

Image: Creating a new project in Google Earth

Image: Exporting the KML file

An example for a KML document is given below:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<Placemark>
  <name>New York City</name>
  <description>New York City</description>
  <Point>
    <coordinates>-74.006393,40.714172,0</coordinates>
  </Point>
</Placemark>
</Document>
</kml>

Parsing through the KML file to extract the location co-ordinates:

An function file ‘kml2struct’ is created to extract the latitude and longitude of the co-ordinates from the KML file.


The Google Earth .kml file of points, lines, polygons, or a combination is imported as a MATLAB struct, compatible with the Mapping Toolbox features, and with shapefiles imported with shaperead().

Structs are composed of the following fields:

- Geometry
- Name
- Description
- Lon
- Lat
- BoundingBox

Mapping Toolbox polygons require a clockwise convention to specify between negative and positive areas. These are not specified in .kml files, so all polygons are converted to clockwise orientation to guarantee that they represent positive space.

Function 'kml2struct' :

function kmlStruct = kml2struct(kmlFile)
% kmlStruct = kml2struct(kmlFile)
%
% Import a .kml file as a vector array of shapefile structs, with Geometry, Name,
% Description, Lon, Lat, and BoundaryBox fields.  Structs may contain a mix
% of points, lines, and polygons.
%
% .kml files with folder structure will not be presented as such, but will
% appear as a single vector array of structs.
%
% 

[FID msg] = fopen(kmlFile,'rt');

if FID<0
    error(msg)
end

txt = fread(FID,'uint8=>char')';
fclose(FID);

expr = '<Placemark.+?>.+?</Placemark>';

objectStrings = regexp(txt,expr,'match');

Nos = length(objectStrings);

for ii = 1:Nos
    % Find Object Name Field
    bucket = regexp(objectStrings{ii},'<name.*?>.+?</name>','match');
    if isempty(bucket)
        name = 'undefined';
    else
        % Clip off flags
        name = regexprep(bucket{1},'<name.*?>\s*','');
        name = regexprep(name,'\s*</name>','');
    end
    
    % Find Object Description Field
    bucket = regexp(objectStrings{ii},'<description.*?>.+?</description>','match');
    if isempty(bucket)
        desc = '';
    else
        % Clip off flags
        desc = regexprep(bucket{1},'<description.*?>\s*','');
        desc = regexprep(desc,'\s*</description>','');
    end
    
    geom = 0;
    % Identify Object Type
    if ~isempty(regexp(objectStrings{ii},'<Point', 'once'))
        geom = 1;
    elseif ~isempty(regexp(objectStrings{ii},'<LineString', 'once'))
        geom = 2;
    elseif ~isempty(regexp(objectStrings{ii},'<Polygon', 'once'))
        geom = 3;
    end
    
    switch geom
        case 1
            geometry = 'Point';
        case 2
            geometry = 'Line';
        case 3
            geometry = 'Polygon';
        otherwise
            geometry = '';
    end
    
    % Find Coordinate Field
    bucket = regexp(objectStrings{ii},'<coordinates.*?>.+?</coordinates>','match');
    % Clip off flags
    coordStr = regexprep(bucket{1},'<coordinates.*?>(\s+)*','');
    coordStr = regexprep(coordStr,'(\s+)*</coordinates>','');
    % Split coordinate string by commas or white spaces, and convert string
    % to doubles
    coordMat = str2double(regexp(coordStr,'[,\s]+','split'));
    % Rearrange coordinates to form an x-by-3 matrix
    [m,n] = size(coordMat);
    coordMat = reshape(coordMat,3,m*n/3)';
    
    % define polygon in clockwise direction, and terminate
    [Lat, Lon] = poly2ccw(coordMat(:,2),coordMat(:,1));
    if geom==3
        Lon = [Lon;NaN];
        Lat = [Lat;NaN];
    end
    
    % Create structure
    kmlStruct(ii).Geometry = geometry;
    kmlStruct(ii).Name = name;
    kmlStruct(ii).Description = desc;
    kmlStruct(ii).Lon = Lon;
    kmlStruct(ii).Lat = Lat;
    kmlStruct(ii).BoundingBox = [[min(Lon) min(Lat);max(Lon) max(Lat)]];
end

The ‘kml2struct’ function file is run with the 'Mathworks_Apple_Hill.kml' file given as input to the function, and the output obtained is a structure containing the fields Geometry, Name, Longitude, Latitude and Boundaries.

Image: Output of the function ‘kml2struct’ with 'Mathworks_Apple_Hill.kml' file given as input

After obtaining the latitude and longitude of the location by parsing the KML file in MATLAB, the next task is to import roads from the ‘OpenStreetMap’ web service into a driving scenario, and then plot a vehicle following a pre-defined route in the imported road network.

The road network being imported is of the ‘MathWorks Apple Hill Campus’ into an empty driving scenario. The file was downloaded from https://www.openstreetmap.org, which provides access to crowd-sourced map data all over the world.

Image: Exporting the map of MathWorks Apple Hill campus from OpenStreetMap into a .osm file

The next step is to plot the imported road network. To maintain the same alignment with geographic coordinate displays, the X-axis is on the bottom and the Y-axis is on the left. In driving scenarios not imported from maps, the X-axis is on the left and the Y-axis is on the bottom. This alignment is consistent with the Automated Driving Toolbox world coordinate system.

scenario = drivingScenario;
roadNetwork(scenario,'OpenStreetMap','applehill.osm');
plot(scenario)

The latitude and longitude coordinates which the vehicle needs to follow for a driving route in this road network are the loaded. The ‘data’ variable is a structure having two fields: latitude with 100 values defined and longitude with 100 values defined.

data = load('geoRouteAH.mat');
lat = data.latitude;
lon = data.longitude;

Image: ‘data’ structure with latitude and longitude fields

Next, we use the ‘latlon2local’ function to convert the driving route from geographic coordinates to local east-north-up (ENU) Cartesian coordinates used in the driving scenario. For the origin of the ENU coordinate system, we use the geographic road network origin stored in the |GeoReference| property of the scenario. The origin is the first coordinate specified in the driving route. Because the driving route contains only latitudinal and longitudinal data, the altitude is set to 0.

alt = 0;
origin = scenario.GeoReference;
[xEast,yNorth,zUp] = latlon2local(lat,lon,alt,origin);

A vehicle is added to the driving scenario. The converted driving route is specified as the trajectory of the vehicle. The vehicle speed is set at 30 meters per second. The vehicle trajectory is plotted and paused every 0.01 seconds to slow down the simulation.

v = vehicle(scenario,'ClassID',1);
speed = 30;
smoothTrajectory(v,[xEast,yNorth,zUp],speed);

while advance(scenario)
    pause(0.01)
end

The complete m-script to import the OpenStreet Map road network and plot the vehicle route is given below:

%% Import OpenStreetMap Road Network and Plot Route
% Import roads from the OpenStreetMap web service into a driving
% scenario. Then, plot a vehicle following a route in the imported road
% network.


%%
% Import a road network of the MathWorks Apple Hill campus into an empty
% driving scenario. The file was downloaded from
% https://www.openstreetmap.org, which provides access to crowd-sourced
% map data all over the world. The data is licensed under the Open Data
% Commons Open Database License (ODbL),
% https://opendatacommons.org/licenses/odbl/.
%
% Plot the imported road network. To maintain the same alignment with
% geographic coordinate displays, the _X_-axis is on the bottom and the
% _Y_-axis is on the left. In driving scenarios not imported from maps, the
% _X_-axis is on the left and the _Y_-axis is on the bottom. This alignment
% is consistent with the Automated Driving Toolbox(TM) world coordinate
% system.

scenario = drivingScenario;
roadNetwork(scenario,'OpenStreetMap','applehill.osm');
plot(scenario)
%% 
% Load the latitude and longitude coordinates for a driving route in this
% road network.

data = load('geoRouteAH.mat');
lat = data.latitude;
lon = data.longitude;
%%
% Use the <latlon2local> function to convert the driving route from geographic
% coordinates to local east-north-up (ENU) Cartesian coordinates used in
% the driving scenario. For the origin of the ENU coordinate system, use
% the geographic road network origin stored in the |GeoReference| property
% of the scenario. The origin is the first coordinate specified in the
% driving route. Because the driving route contains only latitudinal and
% longitudinal data, set the altitude to 0.
alt = 0;
origin = scenario.GeoReference;
[xEast,yNorth,zUp] = latlon2local(lat,lon,alt,origin);
%%
% Add a vehicle to the driving scenario. Specify the converted driving
% route as the trajectory of the vehicle. Set a vehicle speed of 30 meters
% per second. Plot the vehicle trajectory and pause every 0.01 seconds to
% slow down the simulation.
v = vehicle(scenario,'ClassID',1);
speed = 30;
smoothTrajectory(v,[xEast,yNorth,zUp],speed);

while advance(scenario)
    pause(0.01)
end

The output of the m-script is shown in the below figure, where the vehicle travels along the defined path co-ordinates:

Conclusion:

The following objectives have been achieved in this project:

  • Real-time coordinates of the location ‘MathWorks Apple Hill Campus’ has been obtained from Google Earth and the location has been saved as a KML file.
  • The KML file in MATLAB has been parsed in MATLAB using m-script to extract the location co-ordinates (latitude, longitude).
  • Roads from the location ‘MathWorks Apple Hill Campus’ have been imported using the ‘OpenStreetMap’ web service into a driving scenario.
  • The path taken by a vehicle following a pre-defined route with specified location co-ordinates (latitude, longitude) in the imported road network has been plotted using m-scripting.
Your portfolio, next

Ship work like this
in your own course.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.

Talk to a career counsellor

Free 20-minute call. We'll map the right course to where you want to work.

By submitting you agree to our Terms and Privacy Policy.