CesiumJS is an open-source JavaScript library for creating 3D globes and maps. CesiumJS is an easy-to-integrate and uses the library to create interactive web apps having cross-browser compatibility. This library is used by developers across industries, from aerospace to gaming to smart cities and smart 3d drone data inspection in GIS (Geographic Information System) Mapping systems. In this blog, we are going to discuss how to extract and render GPX files from GoPro to cesium.
Cesium inherits the standard WGS84 globe and other recognized models for geospatial visualization and modification.
Some of the supported standard 3D models in CesiumJS include:
- 3D Tileset
- Pointcloud
- KML/KMZ
- Flight Paths (SRT / GPX / MOV)
- Ortho Map
- 360 Panorama
Table of Contents
GPX file
A GPX file is a GPS data file saved in the GPS Exchange format, an open standard used by many GPS programs. It contains longitude and latitude location data, including waypoints, routes, and tracks. GPX files are saved in XML format, which allows GPS data to be more easily imported and read by multiple programs and web services.
A Typical GPX File Consists of The Following Tags:
<?xml version="1.0" encoding="UTF-8"?> <gpx xmlns="" version="" > <trk> <name>TrackName.mp4</name> <desc>30 fps - GPS (Lat., Long., Alt., 2D speed, 3D speed) [deg,deg,m,m/s,m/s]</desc> <src>GoPro Max</src> <trkseg> <trkpt lat="-19.3382103" lon="146.8317091"> <ele>21.986</ele> <time>2022-06-02T05:00:42.456Z</time> <fix>3d</fix> <hdop>126</hdop> <cmt>altitude system: MSLV; 2dSpeed: 1.221; 3dSpeed: 1.18</cmt> </trkpt> <trkpt lat="-19.5382103" lon="146.8327099"> <ele>21.986</ele> <time>2022-06-02T05:00:42.675Z</time> <fix>3d</fix> <hdop>126</hdop> <cmt>altitude system: MSLV; 2dSpeed: 1.221; 3dSpeed: 1.18</cmt> </trkpt> . . . </trkseg> </trk> </gpx>
GPX Files Store 3 Types of Data:
-
Waypoint:
Includes GPS coordinates of a point. It may also include other descriptive information.
-
Route:
Includes a list of track points, which are waypoints for a turn or stage points, that lead to a destination.
-
Track:
Includes a list of points that describe a path.
Loading GPX file in Cesium Viewer:
- Parse the gpx file manually or using a package (i.e gpxparser )
- Parsing gpx file using gpxparser will provide arrays of Waypoints, Routes, and Track.
- Track array contains the track points and related metadata.
gpxParser {xmlSource: document, metadata: {...}, waypoints: Array(0), tracks: Array(1), routes: Array(0)} metadata: {name: null, desc: null, time: '2022-06-07T02:46:33.105000Z', author: {...}} routes: [] tracks: Array(1) 0: cmt: null desc: null distance: {total: 2453.623233993939, cumul: Array(4973)} elevation: {max: 14.847, min: 10.595, pos: 43.026999999999845, neg: 42.82799999999983, avg: 12.706296802734744} link: {} name: "gopro7-track" number: null points: Array(4973) [0 ... 99] 0: ele: 11.207 lat: -18.2547778 lon: 146.0103143 time: Tue Jun 07 2022 07:46:33 GMT+0500 (Pakistan Standard Time) {}
- Sort the points array with reference to the time attribute.
- Iterate over the track points and maintain an array of Cartesian from longitude, latitude, and elevation attributes to Cartesian3 using Cesium.Cartesian3.fromDegrees();
- Maintain a separate array for timestamps, Cartesians, and Cartographic.
- Pass array of Cartesian and Timestamps along with video file URL to create a visual path using polyline entity.
- Add the entity to Cesium Viewer.
Looking for Cesium Development Team?
Share the details of your request and we will provide you with a full-cycle team under one roof.
function CreateFlightPath(params) { // create the cesium polyline entity - temp ? here or just store data and create dynamically later let entity = { id: Cesium.createGuid(), polyline: { positions: params.positions, width: 4, outlineWidth: 1.0, material: new Cesium.ColorMaterialProperty(Cesium.Color.RED.withAlpha(0.7)), distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0.0, 50000), }, timestamps: params.timeStamps, // store video timestamp in millisecs at each vert -- TEMP whether to include at this level, or have the called add that in as needed Type: "flightPath", linkedVideo: params.videoFilename }; return entity; } let readSuccess = (response) => { let gpx = new gpxParser(); let timestampsMS = []; let tempTimeStamp = []; let lastVert = undefined; let pathVertsCartesian = []; let pathVertsCarto = []; let viewRays = []; gpx.parse(response.data); //parsing gpx file _.sortBy(gpx.tracks[0].points, [function (item) { return item.time; //sorting on the basis of time }]); for (let i = 0; i < gpx.tracks[0].points.length; i++) { /* calculating time difference between two consecutive points */ tempTimeStamp.push(moment(gpx.tracks[0].points[i].time).valueOf() - moment(gpx.tracks[0].points[0].time).valueOf()); } for (let i = 0; i < gpx.tracks[0].points.length - 1; i++) { //maintaining cartesian points let thisVert = Cesium.Cartesian3.fromDegrees(gpx.tracks[0].points[i].lon, gpx.tracks[0].points[i].lat, gpx.tracks[0].points[i].ele) if ((lastVert === undefined) || (Cesium.Cartesian3.distance(thisVert, lastVert) >= minDistance)) { lastVert = thisVert; let tempCarto = Cesium.Cartographic.fromDegrees(gpx.tracks[0].points[i].lon, gpx.tracks[0].points[i].lat, gpx.tracks[0].points[i].ele); pathVertsCarto.push(tempCarto); pathVertsCartesian.push(Cesium.Cartographic.toCartesian(tempCarto)); timestampsMS.push(tempTimeStamp[i]); } } let params = { positions: pathVertsCartesian, timeStamps: timestampsMS, videoFilename: videoFilename, }; let entity = CreateFlightPath(params); //calling function to create visual path entity = window.viewer.entities.add(entity); //adding the entity to viewer return {entity}; }