├── src ├── waiting.gif ├── ecef_path_generator.png ├── ecef.css ├── ecef_path_generator.min.js └── ecef_path_generator.js ├── ecef_path_generator.png ├── LICENSE ├── README.md └── ecef_path_generator.html /src/waiting.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fpdf-easytable/ECEF_path_generator/HEAD/src/waiting.gif -------------------------------------------------------------------------------- /ecef_path_generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fpdf-easytable/ECEF_path_generator/HEAD/ecef_path_generator.png -------------------------------------------------------------------------------- /src/ecef_path_generator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fpdf-easytable/ECEF_path_generator/HEAD/src/ecef_path_generator.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Dan Machado 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ECEF path generator 2 | This is an application that generates ECEF coordinates from a drawn path on a map. 3 | The data generated can be used to generate GPS signal files for applications that 4 | simulate GPS signal [gps-sdr-sim](https://github.com/osqzss/gps-sdr-sim). 5 | 6 | [![ecef-path-generator.png](https://i.postimg.cc/Jhyh4BJD/ecef-path-generator.png)](https://postimg.cc/jWbTM2Mt) 7 | 8 | ## Features 9 | 10 | * ONE file application 11 | * Export as csv containing ECEF coordinates. 12 | * Download the raw data of the drawn path containing speed and altitude. 13 | * Download the drawn path as gpx file. 14 | 15 | ## Quick start: 16 | 17 | * Download [ECEF path generator](https://github.com/fpdf-easytable/ECEF_path_generator/blob/master/ecef_path_generator.html). 18 | 19 | * Open it with your internet browser. 20 | 21 | * Click Settings, input the desire latitude and longitude where the map will be centered. 22 | Also the colours for the trail and mover can be customized. 23 | 24 | * Over the map, draw a path using the mouse while pressing the left button, if it is needed 25 | you can delete the last points drawn with the button Remove. 26 | 27 | * Adjust the initial speed: 28 | - key W increment speed by 5km and Q decrement it by 5km, 29 | - key S increment speed by 2km and A decrement it by 2km, 30 | - key X increment speed by 1km and Z decrement it by 1km, 31 | - right arrow increment speed by 0.5km and left arrow decrement it by 0.5km, 32 | 33 | * Adjust the altitude with up arrow (increment) and down arrow (decrement), altitued is in meters. 34 | 35 | * Adjust the initial time elapsed. At x1 this means that the mover will take 15 seconds 36 | on a 1 kilometre path at 240 km/hr, at x2 it will take 7.5 (of real time), 37 | at x4 3.75 sec (of real time) and so on. This will not affect the recording. 38 | 39 | * Click "Recorder / Player", click Record, a blue point will start moving along the drawn path. 40 | You can modify the speed as you wish. 41 | 42 | * After finishes the recording, you can see the result by pressing the Play button. 43 | 44 | * Zoom can be adjusted at any time. 45 | 46 | * Center the map to any point clicked on the map. 47 | 48 | ## Documentation 49 | 50 | * *Recorder / Player* 51 | * **Record** starts to record the position and speed of the mover. Once the recording has finished, speed can not be change. However it can be reset. 52 | * **Reset** reset the path ready to be recorded again from the beginning. Speed is override. 53 | * **Delete** delete the current path. 54 | * **Remove** as far as the path has not been recorded, clicking remove will remove the last point of the path, click it as needed to remove the many point. 55 | * **Append** allows to add more points to the path. After recording a path, you can add more points to it by clicking Reset. 56 | 57 | * *More Actions* 58 | * **Set View** clicking this button will allow you to center the map on the location selected by clicking on the map with the mouse's left button. Click it again to draw a path. 59 | * **Settings** here you can set the latitude, longitude, altitude, zoom and colour for the path and mover. 60 | * **Export to ECEF** after recording, you can download the path in ECEF coordinates, you will need to input the frequency in Hertz for the sample data. To use with [gps-sdr-sim](https://github.com/osqzss/gps-sdr-sim") the sampling rate of the user motion has to be 10Hz. 61 | * **Download Raw Data** this allows you to download the raw data a path was recorded, so you can import it later to play it, reset and change the speed and generate a different ECEF coordinate file. 62 | * **Download GPX** export the path as gpx. The gpx format is widely supported by various GPS devices and software, making it a standard choice for outdoor enthusiasts and professionals. 63 | 64 | ## GPX 65 | 66 | The main objective of this application is to generate ECEF coordinates for gps simulators 67 | that use that kind of data. However we can export the raw data as a basic gpx file. -------------------------------------------------------------------------------- /src/ecef.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | padding: 0; margin: 0; 4 | } 5 | 6 | * { 7 | -webkit-user-select: none; 8 | -khtml-user-select: none; 9 | -moz-user-select: -moz-none; 10 | -o-user-select: none; 11 | user-select: none; 12 | } 13 | 14 | /* 15 | input { 16 | -webkit-user-select: text; 17 | -khtml-user-select: text; 18 | -moz-user-select: text; 19 | -o-user-select: text; 20 | user-select: text; 21 | }//*/ 22 | 23 | body { 24 | background: #fff; 25 | padding: 1px; 26 | } 27 | 28 | .row::after { 29 | content: ""; 30 | clear: both; 31 | display: table; 32 | 33 | } 34 | 35 | [class*="col-"] { 36 | float: left; 37 | padding: 15px; 38 | } 39 | 40 | html { 41 | font-family: "Lucida Sans", sans-serif; 42 | } 43 | 44 | ul { 45 | list-style-type: none; 46 | margin: 0; 47 | padding: 0; 48 | } 49 | 50 | #gadgets li{ 51 | margin-bottom: 15px; 52 | font-size:14px; 53 | text-align:right 54 | } 55 | 56 | .menus li { 57 | padding: 8px; 58 | margin-bottom: 7px; 59 | background-color: #33b5e5; 60 | color: #ffffff; 61 | box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); 62 | text-align:center; 63 | } 64 | 65 | .menus li:hover { 66 | background-color: #0099cc; 67 | } 68 | 69 | .aside { 70 | background-color: #33b5e5; 71 | padding: 15px; 72 | color: #ffffff; 73 | text-align: center; 74 | font-size: 14px; 75 | box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); 76 | } 77 | 78 | #speed-panel { 79 | text-align:left; 80 | margin:0px; 81 | } 82 | 83 | 84 | @media only screen and (min-width: 600px) { 85 | /* For tablets: */ 86 | .col-s-1 {width: 8.33%;} 87 | .col-s-2 {width: 16.66%;} 88 | .col-s-3 {width: 25%;} 89 | .col-s-4 {width: 33.33%;} 90 | .col-s-5 {width: 41.66%;} 91 | .col-s-6 {width: 50%;} 92 | .col-s-7 {width: 58.33%;} 93 | .col-s-8 {width: 66.66%;} 94 | .col-s-9 {width: 75%;} 95 | .col-s-10 {width: 83.33%;} 96 | .col-s-11 {width: 91.66%;} 97 | .col-s-12 {width: 100%;} 98 | } 99 | @media only screen and (min-width: 768px) { 100 | /* For desktop: */ 101 | .col-1 {width: 8.33%;} 102 | .col-2 {width: 16.66%;} 103 | .col-3 {width: 25%;} 104 | .col-4 {width: 33.33%;} 105 | .col-5 {width: 41.66%;} 106 | .col-6 {width: 50%;} 107 | .col-7 {width: 58.33%;} 108 | .col-8 {width: 66.66%;} 109 | .col-9 {width: 75%;} 110 | .col-10 {width: 83.33%;} 111 | .col-11 {width: 91.66%;} 112 | .col-12 {width: 100%;} 113 | } 114 | 115 | /* ############################ */ 116 | 117 | 118 | #canvasContainer { 119 | width:100%; 120 | border:1px solid black; 121 | position:relative; 122 | } 123 | 124 | #canvas { 125 | width:100%; 126 | position:absolute; 127 | z-index:80; 128 | } 129 | 130 | #map { 131 | width:100%; 132 | position:absolute; 133 | z-index:10; 134 | } 135 | 136 | /*####################################################################*/ 137 | 138 | #sbar{ 139 | margin:5px; 140 | height:24px; 141 | padding:1px; 142 | } 143 | 144 | /*#################################################################*/ 145 | div.cntBotton{ 146 | margin:10px 0px; 147 | line-height:37px; 148 | text-align:center; 149 | background-color: #33b5e5; 150 | color: #ffffff; 151 | font-size:18px; 152 | } 153 | 154 | div.cntBotton:hover{ 155 | background-color: #00ffff; 156 | font-weight:bold; 157 | } 158 | 159 | 160 | .clear{ 161 | clear:both; 162 | } 163 | .fLeft{ 164 | float:left; 165 | } 166 | .fRight{ 167 | float:right; 168 | } 169 | 170 | 171 | #speed{ 172 | color:#0066cc; 173 | } 174 | 175 | #distance { 176 | color:#00b300; 177 | } 178 | 179 | #altitude{ 180 | color: #e8ef13; /*#1f14bc;//*/ 181 | } 182 | 183 | #Tdistance , #elapsedtime { 184 | } 185 | 186 | .font1{ 187 | font-size: 25px; 188 | } 189 | 190 | 191 | input[type="file"] { 192 | display: none; 193 | } 194 | 195 | .custom-btn { 196 | border: 1px solid #0066cc; 197 | display: inline-block; 198 | width:100%; 199 | text-align:center; 200 | padding: 10px 12px; 201 | cursor: pointer; 202 | } 203 | 204 | .custom-btn:hover { 205 | background-color: #00ffff; 206 | } 207 | 208 | /*####################################################################*/ 209 | 210 | .slider { 211 | -webkit-appearance: none; 212 | width: 100%; 213 | height: 5px; 214 | background: #d3d3d3; 215 | outline: none; 216 | opacity: 0.7; 217 | -webkit-transition: .2s; 218 | transition: opacity .2s; 219 | margin:0px; 220 | } 221 | 222 | .slider:hover { 223 | opacity: 2; 224 | } 225 | 226 | .slider::-webkit-slider-thumb { 227 | -webkit-appearance: none; 228 | appearance: none; 229 | width: 25px; 230 | height: 25px; 231 | background: #0066cc; 232 | cursor: pointer; 233 | } 234 | 235 | .slider::-moz-range-thumb { 236 | width: 25px; 237 | height: 25px; 238 | background: #0066cc; 239 | cursor: pointer; 240 | } 241 | 242 | /* ############################################################### */ 243 | /* ############################################################### */ 244 | 245 | /*----- PopUP ============================ */ 246 | 247 | #dim 248 | { 249 | position:fixed; 250 | top: 0px; 251 | left: 0px; 252 | width: 100%; 253 | height:200em; 254 | background: #a1a1a1; 255 | z-index: 1000; 256 | opacity:0.40; 257 | display:none; 258 | filter:Alpha(opacity=0); /* IE8 and earlier */ 259 | } 260 | 261 | #pop_wrapper 262 | { 263 | position:fixed; 264 | width: 100%; 265 | height:0px; 266 | top:0px; 267 | left:0px; 268 | visibility:hidden; 269 | filter:Alpha(opacity=0); /* IE8 and earlier */ 270 | -webkit-transition: opacity 0.7s; 271 | -moz-transition: opacity 0.7s; 272 | -ms-transition: opacity 0.7s; 273 | -o-transition: opacity 0.7s; 274 | transition: opacity 0.7s; 275 | z-index:1001; 276 | text-align: center; 277 | } 278 | 279 | #pop_up 280 | { 281 | position: relative; 282 | display: inline-block; 283 | background:#ffffff; 284 | border-radius: 5px; 285 | } 286 | 287 | #pop_up_content 288 | { 289 | padding:20px; 290 | overflow-y:auto; 291 | max-height:600px; 292 | } 293 | 294 | #pop_up_header 295 | { 296 | background:#4c9df1; 297 | line-height:20px; 298 | text-align:left; 299 | padding:5px; 300 | color:#fff; 301 | } 302 | 303 | #popup_content 304 | { 305 | padding:5px; 306 | } 307 | #popup_content > div 308 | { 309 | display:none; 310 | } 311 | 312 | #closePopUp 313 | { 314 | float:right; 315 | margin-right:4px; 316 | font-size:16px; 317 | font-weight:bold; 318 | cursor:default; 319 | } 320 | 321 | .abcr td{ 322 | padding:3px; 323 | } 324 | 325 | .tleft{ 326 | text-align:right; 327 | } 328 | .tright{ 329 | text-align:left; 330 | } 331 | /*###########################################*/ 332 | /*###########################################*/ 333 | .flex-container { 334 | display: flex; 335 | justify-content: space-around; 336 | } 337 | 338 | .flex-container > div { 339 | /* vtext-align: center;*/ 340 | } 341 | 342 | .divRow{ 343 | display:table-row; 344 | } 345 | .divCell{ 346 | display:table-row; 347 | } 348 | 349 | /* ############################################################### */ 350 | 351 | #squareList{ 352 | list-style-position: inside; 353 | list-style-type: square; 354 | } 355 | 356 | #squareList li{ 357 | padding:10px; 358 | } 359 | 360 | #docList{ 361 | list-style-position: inside; 362 | list-style-type: initial; 363 | } 364 | 365 | #docList li{ 366 | padding:10px; 367 | } 368 | 369 | #docList ul{ 370 | list-style-position: inside; 371 | list-style-type: circle; 372 | } 373 | 374 | -------------------------------------------------------------------------------- /src/ecef_path_generator.min.js: -------------------------------------------------------------------------------- 1 | function roundNumber(t,e){var n="number"==typeof e?e:2;return(Math.round(t*Math.pow(10,n))/Math.pow(10,n)).toFixed(e)}function readSingleFile(t){var e=t.target.files[0];e&&((t=new FileReader).readAsText(e,"UTF-8"),t.onload=function(t){drawer.upload(t.target.result.toString())})}const defaultZoom=13.5;function ReadCookie(){cookies={};for(var t,e,n=document.cookie.split(";"),o=0;on&&xo&&yn&&xo&&yOpenStreetMap contributors'}).addTo(map),L.control.scale({maxWidth:300}).addTo(map);var mkObjectEvt=function(){var e={addHandler:function(t,e){this.handlers[t]=this.handlers[t]||[],this.handlers[t].push(e)},fire:function(t){for(var e in this.handlers[t])this.handlers[t][e].apply(null,Array.prototype.slice.call(arguments,1))}};return function(){var t=Object.create(e);return t.handlers={},t}}();controlModule=mkObjectEvt(),controlModule.playButton=document.getElementById("playButton"),controlModule.pauseButton=document.getElementById("pauseButton"),controlModule.recordButton=document.getElementById("recordButton"),controlModule.recordingButton=document.getElementById("recordingButton"),controlModule.deleteButton=document.getElementById("deletButton"),controlModule.eraseButton=document.getElementById("eraseButton"),controlModule.appendButton=document.getElementById("appendButton"),controlModule.resetButton=document.getElementById("resetButton"),controlModule.exportButton=document.getElementById("export"),controlModule.exportDataButton=document.getElementById("exportData"),controlModule.exportGPXButton=document.getElementById("exportGPX"),controlModule.disableButtons=function(t){controlModule.deleteButton.disabled=t,controlModule.eraseButton.disabled=t,controlModule.appendButton.disabled=t,controlModule.resetButton.disabled=t,controlModule.exportButton.disabled=t,controlModule.exportDataButton.disabled=t,controlModule.exportGPXButton.disabled=t},controlModule.addHandler("reset",function(){controlModule.pauseButton.style.display="none",controlModule.playButton.style.display="none",controlModule.recordingButton.style.display="none",controlModule.recordButton.style.display="block",controlModule.disableButtons(!1)}),controlModule.init=function(){document.getElementById("upload").addEventListener("change",readSingleFile);var e=globalSettings.baseZ;controlModule.setZoom=function(t){(e=.25*Math.floor(t/.25))<12&&(e=globalSettings.baseZ),map.setZoom(e)},document.getElementById("zoom_less").addEventListener("click",function(){11<=e-.25&&(e-=.25,map.setZoom(e))}),document.getElementById("zoom_more").addEventListener("click",function(){e+.25<=17&&(e+=.25,map.setZoom(e))});var n=1;controlModule.setSpeedTime=function(t){0this.mxG){this.head;var i=Math.ceil(o/this.mxG),s=1;t-this.lastX<0&&(s=-1);var a=1;e-this.lastY<0&&(a=-1);for(var r=Math.abs(t-this.lastX)/i,d=Math.abs(e-this.lastY)/i,l=1;lthis.mxG||0==this.head)&&(Trail.addPoint(t,e),this.head++,gadgetModule.totalDistance.innerHTML=roundNumber(Trail.getTrailLengthKm(),2))}},deleteLast:function(){0",t+=""+document.getElementById("gpxDesc").value.trim()+"",t+="",document.getElementById("gpxDesc").value="";for(var n=roundNumber(this.wkDistance,3),i=document.getElementById("elapsedtime").innerHTML,s=0,a=0;a"+e+"",t+="Blue",t+=""+n+"",t+=""+i+"",t+=""+s+"",t+=""+r+"",t+=""+d+"",t+="";for(a=0;a';t+="",download(e+".gpx",t,"data:text/xml;charset=utf-8;")}else download(e+".txt",JSON.stringify(o),"data:text/plain;charset=utf-8;")},upload:function(t){var e;this.erase();try{e=JSON.parse(t.toString())}catch(t){return void alert("File could not be loaded because it has bad syntax or it's corrupted.")}if(e.hasOwnProperty("coordinates")){let t=defaultZoom;e.hasOwnProperty("zoom")&&(t=e.zoom),this.setCoordinates(e.coordinates.lat,e.coordinates.lng,t)}if(this.head=0,e.hasOwnProperty("trail"))for(var n=0;n=e&&(this.speed-=e),this.speed<=0&&(this.speed=.5)):this.speed<=this.maxSpeed-e?this.speed+=e:this.speed=this.maxSpeed,document.getElementById("speed").innerHTML=roundNumber(this.speed,2)},setSpeed:function(t){this.speed=Math.abs(t),document.getElementById("speed").innerHTML=roundNumber(this.speed,2)}};function download(t,e,n){e=new Blob([e],{type:n});window.navigator.msSaveBlob?navigator.msSaveBlob(e,t):((n=document.createElement("a")).setAttribute("href",URL.createObjectURL(e)),n.setAttribute("download",t),n.style.display="none",document.body.appendChild(n),n.click(),document.body.removeChild(n)),popUpAPI.closing()}drawer.init(),controlModule.setZoom(13.5),window.addEventListener("keydown",function(t){38==t.keyCode||40==t.keyCode?controlModule.changeAltitude(t.keyCode):37!=t.keyCode&&39!=t.keyCode&&81!=t.keyCode&&87!=t.keyCode&&65!=t.keyCode&&83!=t.keyCode&&88!=t.keyCode&&90!=t.keyCode||drawer.changeSpeed(t.keyCode)}),document.onkeydown=function(t){t=(t=t||window.event).keyCode;if(37<=t&&t<=40)return!1},window.addEventListener("DOMContentLoaded",function(){var e,n,t,o;window.scrollTo(0,0),e=document.getElementById("dim"),n=document.getElementById("pop_wrapper"),t=document.getElementById("pop_up"),o=document.getElementById("popup_content"),n.style.top=.1*window.innerHeight+"px",t.style.maxHeight=.8*window.innerHeight+"px",popUpAPI={display:function(){e.style.display="block",n.style.visibility="visible"},closing:function(t){void 0===t?(n.style.visibility="hidden",e.style.display="none",document.getElementById("ecef").style.display="none",document.getElementById("rawData").style.display="none",document.getElementById("gpxData").style.display="none",document.getElementById("configuration").style.display="none",document.getElementById("description").style.display="none"):t.stopPropagation()},exportECEF:function(){document.getElementById("popup_title").innerHTML="Export to ECEF",document.getElementById("ecef").style.display="block",this.display()},processECEF:function(){var t=document.getElementById("frequency"),e=document.getElementById("fileName"),n=Number(t.value.trim());Number.isInteger(n)&&0!=n?e.value.trim()?(popUpAPI.wait(),drawer.changeFrequency(n),drawer.processData(e.value.trim()),t.value="",e.value=""):alert("Please enter a valid file name."):alert("Please enter a valid integer frequency.")},download:function(){document.getElementById("popup_title").innerHTML="Download Path Configuration",document.getElementById("rawData").style.display="block",this.display()},downloadGPX:function(){document.getElementById("popup_title").innerHTML="Download Path GPX",document.getElementById("gpxData").style.display="block",this.display()},settingsECEF:function(){document.getElementById("popup_title").innerHTML="Settings",document.getElementById("configuration").style.display="block",this.display()},whatisit:function(){document.getElementById("popup_title").innerHTML="Description",document.getElementById("description").style.display="block",this.display()},wait:function(){document.getElementById("popup_title").innerHTML="Processing data",this.display()},processDownload:function(t,e,n){t.value.trim()?(drawer.downloadData(t.value.trim(),n),t.value="",this.closing(),document.getElementById(e).style.display="none"):alert("Please enter a valid file name.")}},document.getElementById("closePopUp").addEventListener("click",function(){popUpAPI.closing()}),e.addEventListener("click",function(){popUpAPI.closing()}),n.addEventListener("click",function(){popUpAPI.closing()}),o.addEventListener("click",function(t){popUpAPI.closing(t)}),document.getElementById("export").addEventListener("click",function(){popUpAPI.exportECEF()}),document.getElementById("settings").addEventListener("click",function(){popUpAPI.settingsECEF()}),document.getElementById("ecefButton").addEventListener("click",function(){popUpAPI.processECEF()}),document.getElementById("exportData").addEventListener("click",function(){popUpAPI.download()}),document.getElementById("exportGPX").addEventListener("click",function(){popUpAPI.downloadGPX()}),document.getElementById("moveToBtn").addEventListener("click",function(){drawer.getPositionFromPointer=!drawer.getPositionFromPointer&&drawer.canMove(),drawer.getPositionFromPointer?document.getElementById("moveToBtn").style.fontWeight="bold":document.getElementById("moveToBtn").style.fontWeight="normal"}),document.getElementById("canvasContainer").addEventListener("mousedown",function(t){drawer.getPositionFromPointer&&globalSettings.getPosition3(function(e,n){var t=globalSettings.containerPointToLatLng(e,n);drawer.setCoordinates(t.lat,t.lng,map.getZoom()),map.once("moveend",function(){var t=globalSettings.containerCenter();t.add2(-1*e,-1*n),Trail.onTranslate(t.x,t.y)}.bind(this))},t)}),document.getElementById("whatisit").addEventListener("click",function(){popUpAPI.whatisit()}),document.getElementById("rawDataButton").addEventListener("click",function(){popUpAPI.processDownload(document.getElementById("fileNameR"),"rawData","txt")}),document.getElementById("gpxDataButton").addEventListener("click",function(){popUpAPI.processDownload(document.getElementById("gpxNameR"),"gpxData","gpx")}),document.getElementById("locationButton").addEventListener("click",function(){var t=Number(document.getElementById("latitude").value),e=Number(document.getElementById("longitude").value);Number.isNaN(t)||Number.isNaN(e)?alert("Please enter a valid number."):(drawer.setCoordinates(t,e,defaultZoom),document.cookie="longitude="+e,document.cookie="latitude="+t)}),document.getElementById("coloursButton").addEventListener("click",function(){var t=document.getElementById("trail_colour").value,e=document.getElementById("mover_colour").value;""==(t=t.trim())&&(t="#ffb366"),""==(e=e.trim())&&(e="blue"),Trail.setColours(t,e)}),""==document.cookie&&(document.cookie="whatisit=yes"),o=ReadCookie(),drawer.setCoordinates(o.lat,o.lng,defaultZoom)}); -------------------------------------------------------------------------------- /ecef_path_generator.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | ECEF Path Generator 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
43 |
44 | 45 | × 46 |
47 |
48 | 198 |
199 |
200 | 201 | 202 | 203 |
204 |
205 |
206 |
    207 |
  • 208 |
    Speed
    209 |
    0.00
    210 |
    km/h
    211 |
  • 212 |
  • 213 |
    Total Distance
    214 |
    0.00
    215 |
    km
    216 |
  • 217 |
  • 218 |
    Distance
    219 |
    0.00
    220 |
    km
    221 |
  • 222 |
  • 223 |
    Altitude
    224 |
    0.00
    225 |
    mt
    226 |
  • 227 |
  • 228 |
    Time
    229 |
    0.00
    230 |
    secs
    231 |
  • 232 |
233 | 234 | 235 | 236 |
237 |
238 |
239 | 240 | 241 | 242 | 243 |
244 |
245 |
246 |
247 | 248 | 249 |
250 |
251 | 252 |
253 |
254 | 255 | 256 |
257 |
258 | 259 |
260 | 261 |
262 |
Time Elapsed
263 | 264 |
x1
265 | 266 |
267 | 268 |
269 | 270 |
271 |
272 |
Zoom
273 | 274 | 275 |
276 | 277 | 278 |
279 | 280 |
281 |
282 | 283 | 284 | 285 | 291 | 292 | 293 |
294 |
295 |
296 | 297 | 298 | 299 |
300 |
301 | 302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 | 312 | 313 | 314 | 315 | 316 | 317 | 328 | 329 | 330 | 331 | 332 | -------------------------------------------------------------------------------- /src/ecef_path_generator.js: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * ecef_path_generator.js * 3 | * * 4 | * Version: 2.0 * 5 | * Date: 28-01-2022 * 6 | * Author: Dan Machado * 7 | * Require raphaeljs v2.2.1 * 8 | **********************************************************************/ 9 | 10 | function roundNumber(x, p){ 11 | var d=2; 12 | if(typeof p==='number') { 13 | d=p; 14 | } 15 | return (Math.round(x* Math.pow(10, d))/Math.pow(10,d)).toFixed(p); 16 | } 17 | 18 | //################################################################## 19 | 20 | //to load a file 21 | function readSingleFile(e) { 22 | var file = e.target.files[0]; 23 | if(!file){ 24 | return; 25 | } 26 | 27 | var reader = new FileReader(); 28 | reader.readAsText(file, "UTF-8"); 29 | reader.onload = function(e) { 30 | drawer.upload(e.target.result.toString()); 31 | }; 32 | } 33 | 34 | //################################################################## 35 | 36 | const defaultZoom=13.50; 37 | 38 | function ReadCookie(){ 39 | cookies={}; 40 | var allcookies = document.cookie; 41 | var cookiearray = allcookies.split(';'); 42 | 43 | for(var i=0; i0){ 247 | for(var i=0; ilx && xly && ylx && xly && yOpenStreetMap contributors' 405 | }).addTo(map); 406 | 407 | L.control.scale({maxWidth:300}).addTo(map); 408 | 409 | //map.setView([53.2672, -1.63], Settings.initialZoom()); 410 | 411 | //#################################################################### 412 | //#################################################################### 413 | 414 | var mkObjectEvt=(function(){ 415 | var objectEvent={ 416 | addHandler:function(evt,ck){ 417 | this.handlers[evt]=this.handlers[evt] || []; 418 | this.handlers[evt].push(ck); 419 | }, 420 | fire:function(evt){ 421 | for(var i in this.handlers[evt]){ 422 | this.handlers[evt][i].apply(null, Array.prototype.slice.call(arguments, 1)); 423 | } 424 | }, 425 | }; 426 | 427 | return function(){ 428 | var module=Object.create(objectEvent); 429 | module.handlers={}; 430 | 431 | return module; 432 | } 433 | })(); 434 | 435 | //#################################################################### 436 | //#################################################################### 437 | 438 | (function(){ 439 | controlModule=mkObjectEvt(); 440 | controlModule.playButton=document.getElementById('playButton'); 441 | controlModule.pauseButton=document.getElementById('pauseButton'); 442 | controlModule.recordButton=document.getElementById('recordButton'); 443 | controlModule.recordingButton=document.getElementById('recordingButton'); 444 | controlModule.deleteButton=document.getElementById('deletButton'); 445 | controlModule.eraseButton=document.getElementById('eraseButton'); 446 | controlModule.appendButton=document.getElementById('appendButton'); 447 | controlModule.resetButton=document.getElementById('resetButton'); 448 | 449 | controlModule.exportButton=document.getElementById('export'); 450 | controlModule.exportDataButton=document.getElementById('exportData'); 451 | controlModule.exportGPXButton=document.getElementById('exportGPX'); 452 | 453 | controlModule.disableButtons=function(enable){ 454 | controlModule.deleteButton.disabled = enable; 455 | controlModule.eraseButton.disabled = enable; 456 | controlModule.appendButton.disabled = enable; 457 | controlModule.resetButton.disabled = enable; 458 | controlModule.exportButton.disabled=enable; 459 | controlModule.exportDataButton.disabled=enable; 460 | controlModule.exportGPXButton.disabled=enable; 461 | }; 462 | 463 | controlModule.addHandler('reset', function(){ 464 | controlModule.pauseButton.style.display='none'; 465 | controlModule.playButton.style.display='none'; 466 | controlModule.recordingButton.style.display='none'; 467 | controlModule.recordButton.style.display='block'; 468 | 469 | controlModule.disableButtons(false); 470 | }); 471 | 472 | controlModule.init=function(){ 473 | document.getElementById('upload').addEventListener('change', readSingleFile); 474 | 475 | var zoomVal=globalSettings.baseZ; 476 | var zoomStep=0.25; 477 | controlModule.setZoom=function(zoomLevel){ 478 | zoomVal=zoomStep*Math.floor(zoomLevel/zoomStep); 479 | if(zoomVal<12){ 480 | zoomVal=globalSettings.baseZ; 481 | } 482 | map.setZoom(zoomVal); 483 | }; 484 | document.getElementById('zoom_less').addEventListener('click', function(){ 485 | if(zoomVal-0.25>=11){ 486 | zoomVal-=0.25; 487 | map.setZoom(zoomVal); 488 | } 489 | }); 490 | 491 | document.getElementById('zoom_more').addEventListener('click', function(){ 492 | if(zoomVal+0.25<=17.0){ 493 | zoomVal+=0.25; 494 | map.setZoom(zoomVal); 495 | } 496 | }); 497 | 498 | var xT=1; 499 | controlModule.setSpeedTime=function(xt){ 500 | if(xt>0 && xt<6){ 501 | xT=xt; 502 | controlModule.fire('timeFactor', xT); 503 | document.getElementById('x_time').innerHTML='x'+xT; 504 | } 505 | }; 506 | document.getElementById('time_speed_less').addEventListener('click', function(){ 507 | if(xT>1){ 508 | xT--; 509 | controlModule.setSpeedTime(xT); 510 | } 511 | }); 512 | 513 | document.getElementById('time_speed_more').addEventListener('click', function(){ 514 | if(xT<5){ 515 | xT++; 516 | controlModule.setSpeedTime(xT); 517 | } 518 | }); 519 | 520 | this.playButton.addEventListener('click', function () { 521 | controlModule.fire('play'); 522 | controlModule.playButton.style.display='none'; 523 | controlModule.pauseButton.style.display='block'; 524 | }); 525 | 526 | this.pauseButton.addEventListener('click', function () { 527 | controlModule.fire('pause'); 528 | controlModule.pauseButton.style.display='none'; 529 | controlModule.playButton.style.display='block'; 530 | }); 531 | 532 | this.recordButton.addEventListener('click', function () { 533 | controlModule.recordButton.style.display='none'; 534 | controlModule.recordingButton.style.display='block'; 535 | controlModule.disableButtons(true); 536 | controlModule.fire('record'); 537 | }); 538 | 539 | this.deleteButton.addEventListener('click', function () { 540 | controlModule.fire('delete'); 541 | controlModule.pauseButton.style.display='none'; 542 | controlModule.playButton.style.display='none'; 543 | controlModule.recordingButton.style.display='none'; 544 | controlModule.recordButton.style.display='block'; 545 | 546 | controlModule.eraseButton.disabled=false; 547 | controlModule.appendButton.disabled=false; 548 | 549 | controlModule.exportButton.disabled=true; 550 | controlModule.exportDataButton.disabled=true; 551 | controlModule.exportGPXButton.disabled=true; 552 | }); 553 | 554 | this.resetButton.addEventListener('click', function () { 555 | controlModule.fire('reset'); 556 | controlModule.exportButton.disabled=true; 557 | controlModule.exportDataButton.disabled=true; 558 | controlModule.exportGPXButton.disabled=true; 559 | }); 560 | 561 | this.eraseButton.addEventListener('click', function () { 562 | controlModule.fire('erase'); 563 | }); 564 | 565 | this.appendButton.addEventListener('click', function () { 566 | controlModule.fire('append'); 567 | }); 568 | 569 | this.addHandler('readyToPlay', function(){ 570 | controlModule.pauseButton.style.display='none'; 571 | controlModule.playButton.style.display='block'; 572 | }); 573 | 574 | this.addHandler('recordingFinished', function(){ 575 | controlModule.recordingButton.style.display='none'; 576 | controlModule.recordButton.style.display='none'; 577 | controlModule.playButton.style.display='block'; 578 | controlModule.disableButtons(false); 579 | controlModule.eraseButton.disabled=true; 580 | controlModule.appendButton.disabled=true; 581 | }); 582 | }; 583 | 584 | controlModule.altitude=10; 585 | 586 | controlModule.setAltitude=function(altitude){ 587 | controlModule.altitude=Math.abs(altitude); 588 | controlModule.fire('altitudeChanged', controlModule.altitude); 589 | }; 590 | 591 | controlModule.changeAltitude=function(code){ //z=90=down; x=88=up 592 | var altStep=5; 593 | var maxAlt=1500; 594 | if(code==40){// down key 595 | if(controlModule.altitude>=altStep){ 596 | controlModule.altitude-=altStep; 597 | } 598 | else{ 599 | //this.altitude=0; 600 | } 601 | } 602 | else if(code==38){// up key 603 | if(controlModule.altitude0){ 849 | var i=this.set.length-1; 850 | if(i>0){ 851 | this.trailLength-=this.segmentMtLength(i-1); 852 | } 853 | this.set[i].remove(); 854 | this.set.pop(); 855 | } 856 | }, 857 | 858 | trailPOIcolour:"#ffb366", 859 | trailLength:0.0, 860 | mover:null, 861 | 862 | init:function(){ 863 | this.mover=globalSettings.paper.circle(0, 0, 2); 864 | this.mover.attr({stroke:'none', fill: "blue"}); 865 | this.mover.attr({transform: 't-100,-100'}); 866 | }, 867 | 868 | addPoint:function(x, y){ 869 | this.set.push(mkPOI(x, y, {stroke:'none', fill: this.trailPOIcolour})); 870 | this.setUp(); 871 | }, 872 | 873 | addPointLatLng:function(latLng){ 874 | this.set.push(mkPOI(0, 0, {stroke:'none', fill: this.trailPOIcolour})); 875 | var k=this.set.length-1; 876 | this.set[k].setLatLng(latLng); 877 | this.setUp(); 878 | }, 879 | 880 | setUp:function(){ 881 | if(this.set.length>1){ 882 | var i=this.set.length-1; 883 | this.directions.push(mkVect2D(this.getGeoX(i)-this.getGeoX(i-1), (this.getGeoY(i-1)-this.getGeoY(i)))); 884 | this.trailLength+=this.segmentMtLength(i-1); 885 | i=this.directions.length-1; 886 | this.directions[i].normalise(); 887 | } 888 | }, 889 | 890 | getTrailLengthKm:function(){ 891 | return this.trailLength*0.001; 892 | }, 893 | 894 | segmentMtLength:function(idx){ 895 | if(idx0){ 921 | this.currentGeoPos.setPositionAt(this.getGeoX(0),this.getGeoY(0)); 922 | this.mover.attr(globalSettings.mtsCooPxs2(this.currentGeoPos.x, this.currentGeoPos.y)); 923 | this.mover.toFront(); 924 | this.segmentNum=0; 925 | } 926 | }, 927 | 928 | moveToNext:function(time){ 929 | this.currentGeoPos.add(this.deltaGeo); 930 | this.mover.animate(globalSettings.mtsCooPxs2(this.currentGeoPos.x, this.currentGeoPos.y), time, "linear"); 931 | this.mover.toFront(); 932 | }, 933 | 934 | segmentNum:0, 935 | distanceMt:0, 936 | deltaGeo:mkVect2D(0, 0), 937 | 938 | getDelta:(function(){ 939 | var msH=1/3600000;//conversion factor from k/h to k/ms 940 | var sH=1/3600; // conversion from k/h to k/sec 941 | var timeThreshold=250; 942 | var timeStep=300; 943 | var vkms, tms, dm, a; 944 | return function(speed, speedTime){ 945 | if(this.segmentNum+1==this.set.length){ 946 | return {time:-1}; 947 | } 948 | if(this.distanceMt<=0){ 949 | this.distanceMt=this.segmentMtLength(this.segmentNum); 950 | } 951 | 952 | /* 953 | README: initially vkms=speed*msH; 954 | but because we multiply by 0.001 and then by 1000, 955 | better to use this, so we avoid 2 multiplications: 956 | 957 | vkms=speed*msH; 958 | tms=(0.001*this.distanceMt)/vkms; 959 | dm=1000*vkms*tms; 960 | */ 961 | 962 | vkms=speed*sH; 963 | tms=this.distanceMt/vkms; 964 | 965 | a=true; 966 | 967 | if(tms>timeThreshold){//timeThreshold=250; 968 | if(timeStep+250550 //timeStep=300; 969 | tms=timeStep; 970 | a=false; 971 | } 972 | else if(tms>420){ 973 | tms*=0.5; 974 | a=false; 975 | } 976 | } 977 | 978 | dm=vkms*tms; 979 | 980 | this.distanceMt-=dm; 981 | 982 | this.directions[this.segmentNum].copyTo(this.deltaGeo); 983 | this.deltaGeo.multiply(dm); 984 | this.deltaGeo.y*=-1; 985 | this.moveToNext(tms, speedTime); 986 | 987 | if(a){ 988 | this.distanceMt=0; 989 | this.segmentNum++; 990 | } 991 | 992 | return {time:tms, distance:0.001*dm, geoX:this.currentGeoPos.x, geoY:this.currentGeoPos.y}; 993 | }; 994 | })(), 995 | 996 | exportData:function(){ 997 | var dataResult=[]; 998 | for(var i=0; i0 || this.getPositionFromPointer){ 1104 | return; 1105 | } 1106 | var d=0; 1107 | if(this.head>0){ 1108 | var pxC=globalSettings.mtsCoordinatesToPxs(Trail.getGeoX(this.head-1), Trail.getGeoY(this.head-1)); 1109 | this.lastX=pxC.x; 1110 | this.lastY=pxC.y; 1111 | d=distance2DPoints(this.lastX, this.lastY, x, y); 1112 | } 1113 | 1114 | if(d>this.mxG){ 1115 | var k=this.head-1; 1116 | var r=Math.ceil(d/this.mxG); 1117 | var f=1; 1118 | if(x-this.lastX<0){ 1119 | f=-1; 1120 | } 1121 | var g=1; 1122 | if(y-this.lastY<0){ 1123 | g=-1; 1124 | } 1125 | 1126 | var tx=Math.abs(x-this.lastX)/r; 1127 | var ty=Math.abs(y-this.lastY)/r; 1128 | for(var j=1; jthis.mxG || this.head==0){ 1135 | Trail.addPoint(x,y); 1136 | this.head++; 1137 | gadgetModule.totalDistance.innerHTML=roundNumber(Trail.getTrailLengthKm(), 2); 1138 | } 1139 | }, 1140 | 1141 | deleteLast:function(){ 1142 | if(this.status>0 && this.head>1){ 1143 | return; 1144 | } 1145 | 1146 | this.head--; 1147 | Trail.removeLast(); 1148 | if(this.head>0){ 1149 | gadgetModule.totalDistance.innerHTML=roundNumber(Trail.getTrailLengthKm(), 2); 1150 | } 1151 | }, 1152 | 1153 | append:function(){ 1154 | this.status=0; 1155 | }, 1156 | 1157 | counter:0, 1158 | head:0, 1159 | paused:false, 1160 | halt:function(){ 1161 | this.paused=true; 1162 | }, 1163 | isRunning:false, 1164 | speed:1, 1165 | 1166 | play:function(){ 1167 | if(this.paused){ 1168 | gadgetModule.startTimer(); 1169 | this.paused=false; 1170 | this.run(); 1171 | } 1172 | 1173 | if(this.isRunning){ 1174 | return; 1175 | } 1176 | 1177 | this.counter=0; 1178 | this.wkDistance=0; 1179 | this.status=1; 1180 | 1181 | gadgetModule.resetTimer(); 1182 | gadgetModule.startTimer(); 1183 | 1184 | Trail.moveToStart(); 1185 | 1186 | if(this.speed>0){ 1187 | this.isRunning=true; 1188 | this.counter++; 1189 | this.run(); 1190 | } 1191 | }, 1192 | 1193 | wkDistance:0, 1194 | run:(function(){ 1195 | var a=true; 1196 | var idx=0; 1197 | var tm=0; 1198 | return function(){ 1199 | if(this.paused ){ 1200 | return; 1201 | } 1202 | 1203 | if(a){ 1204 | dt=Trail.getDelta(this.speedData[idx+1], this.speedTime); 1205 | 1206 | a=(dt.time>=0) && (idx0){ 1209 | setTimeout(function(){ 1210 | this.run(); 1211 | }.bind(this), dt.time/this.speedTime); 1212 | this.wkDistance+=dt.distance; 1213 | } 1214 | else{ 1215 | this.run(); 1216 | a=true; 1217 | idx=0; 1218 | tm=0; 1219 | } 1220 | if(this.isRunning){ 1221 | gadgetModule.speed.innerHTML=roundNumber(this.speedData[idx], 2); 1222 | gadgetModule.updateAlt(this.altData[idx++]); 1223 | } 1224 | gadgetModule.distance.innerHTML=roundNumber(this.wkDistance, 2); 1225 | gadgetModule.timer(tm); 1226 | tm=dt.time; 1227 | } 1228 | else{ 1229 | gadgetModule.timer(tm);// last bit 1230 | if(this.isRunning){ 1231 | controlModule.fire('readyToPlay'); 1232 | } 1233 | this.isRunning=false; 1234 | } 1235 | } 1236 | }()), 1237 | 1238 | canMove:function(){ 1239 | return !this.isRunning && !this.isRecording; 1240 | }, 1241 | 1242 | resetRecording:true, 1243 | dataR:[], 1244 | timeOutID:0, 1245 | isRecording:false, 1246 | record:(function(){ 1247 | var a=true; 1248 | var tm=0; 1249 | return function(){ 1250 | if(this.head==0){ 1251 | controlModule.fire('reset'); 1252 | this.isRecording=false; 1253 | return; 1254 | } 1255 | 1256 | if(this.resetRecording){ 1257 | a=true; 1258 | tm=0; 1259 | this.resetRecording=false; 1260 | this.dataR.length=0; 1261 | this.dataR.push([Trail.getGeoX(0), Trail.getGeoY(0)]); 1262 | this.speedData.length=0; 1263 | this.speedData.push(this.speed); 1264 | this.altData.length=0; 1265 | this.altData.push(this.altitude); 1266 | Trail.moveToStart(); 1267 | this.status=1; 1268 | gadgetModule.startTimer(); 1269 | } 1270 | 1271 | if(a){ 1272 | this.altData.push(this.altitude); 1273 | this.speedData.push(this.speed); 1274 | dt=Trail.getDelta(this.speed, this.speedTime); 1275 | a=dt.time>=0; 1276 | if(dt.time>0){ 1277 | this.dataR.push([dt.geoX, dt.geoY]); 1278 | 1279 | this.timeOutID=setTimeout(function(){ 1280 | this.record(); 1281 | }.bind(this), dt.time/this.speedTime); 1282 | this.wkDistance+=dt.distance; 1283 | } 1284 | else{ 1285 | this.record(); 1286 | } 1287 | gadgetModule.timer(tm); 1288 | tm=dt.time; 1289 | gadgetModule.distance.innerHTML=roundNumber(this.wkDistance,2); 1290 | } 1291 | else{ 1292 | this.altData.push(this.altitude); 1293 | this.speedData.push(this.speed); 1294 | this.dataR.push([Trail.getLastGeoX(), Trail.getLastGeoY()]); 1295 | controlModule.fire('recordingFinished'); 1296 | this.isRecording=false; 1297 | } 1298 | } 1299 | }()), 1300 | 1301 | clearData:function(){ 1302 | this.dataR.length=0; 1303 | this.speedData.length=0; 1304 | this.altData.length=0; 1305 | }, 1306 | 1307 | erase:function(){ 1308 | this.clearData(); 1309 | this.resetRecording=true; 1310 | this.head=0; 1311 | Trail.reset(); 1312 | gadgetModule.totalDistance.innerHTML='0.00'; 1313 | gadgetModule.distance.innerHTML='0.00'; 1314 | this.counter=0; 1315 | this.wkDistance=0; 1316 | this.isRunning=false; 1317 | this.paused=false; 1318 | this.status=0; 1319 | gadgetModule.resetTimer(); 1320 | this.setSpeed(10); 1321 | }, 1322 | 1323 | reset:function(){ 1324 | this.clearData(); 1325 | this.resetRecording=true; 1326 | gadgetModule.distance.innerHTML='0.00'; 1327 | Trail.moveToStart(); 1328 | this.counter=0; 1329 | this.wkDistance=0; 1330 | this.isRunning=false; 1331 | this.paused=false; 1332 | gadgetModule.resetTimer(); 1333 | gadgetModule.speed.innerHTML=roundNumber(this.speed, 2); 1334 | //controlModule.setAltitude(10); 1335 | }, 1336 | 1337 | segmentLength:function(nespeedTime, prev){ 1338 | return Math.sqrt(Math.pow(nespeedTime[0]-prev[0], 2)+Math.pow(nespeedTime[1]-prev[1], 2)); 1339 | }, 1340 | 1341 | changeFrequency:function(newFrequency){ 1342 | this.frequency=newFrequency; 1343 | }, 1344 | 1345 | isMapReady:false, 1346 | mapReady:function(){ 1347 | return this.isMapReady; 1348 | }, 1349 | setCoordinates:function(lat, lng, zoomLevel){ 1350 | this.offSetX=Number(lng); 1351 | this.offSetY=Number(lat); 1352 | map.setView([Number(lat), Number(lng)], zoomLevel); 1353 | this.isMapReady=true; 1354 | globalSettings.mkGrid(); 1355 | }, 1356 | 1357 | frequency:10, //in Hz (The sampling rate of the user motion has to be 10Hz (for Pluto)) 1358 | toECEF:true, 1359 | 1360 | processData:function(fileName){ 1361 | if(this.dataR.length==0){ 1362 | alert("No data recorded."); 1363 | return; 1364 | } 1365 | 1366 | /* 1367 | km/h -> km/sec -> mt/sec 1368 | km/h *(hr/3600sec)*(1000mt/1km) 1369 | km/h * (1000/3600) 1370 | mt/sec = km/h * (10/36) 1371 | */ 1372 | const mtSec=10.0/36.0; 1373 | const fps=1.0/this.frequency; 1374 | var a=false; 1375 | 1376 | var cos, sin, t, rawDistance, tz=fps;//1.0/this.frequency; 1377 | var dx, dy, cx, cy; 1378 | 1379 | var preData=[]; 1380 | var pt=Number(0.0); 1381 | var Lat=this.offSetY+Conversion.kmToDDNorth(this.dataR[0][1]*0.001); 1382 | var alt=this.altData[0]; 1383 | if(this.toECEF){ 1384 | preData.push([pt.toFixed(1), Conversion.toECEF(Lat, this.offSetX+Conversion.kmToDDEast(Lat, this.dataR[0][0]*0.001), alt)]); 1385 | pt+=0.1; 1386 | } 1387 | else{ 1388 | preData.push([Lat, this.offSetX+Conversion.kmToDDEast(Lat, this.dataR[0][0]*0.001), alt]); 1389 | } 1390 | 1391 | for(var i=1; i=0){ 1418 | cx+=dx; 1419 | cy+=dy; 1420 | Lat=this.offSetY+Conversion.kmToDDNorth(cy*0.001); 1421 | if(this.toECEF){ 1422 | preData.push([pt.toFixed(1), Conversion.toECEF(Lat,this.offSetX+Conversion.kmToDDEast(Lat, cx*0.001), alt)]); 1423 | pt+=0.1; 1424 | } 1425 | else{ 1426 | preData.push([Lat, this.offSetX+Conversion.kmToDDEast(Lat, cx*0.001), alt]); 1427 | } 1428 | 1429 | t-=tz; 1430 | 1431 | if(a){ 1432 | tz=fps; 1433 | dx=cos*tz*spd; 1434 | dy=sin*tz*spd; 1435 | a=false; 1436 | } 1437 | } 1438 | if(t0.001){ 1439 | a=true; 1440 | tz=fps-t; 1441 | } 1442 | } 1443 | 1444 | var result=''; 1445 | var g=(pt.toFixed(1)).toString().length; 1446 | var num; 1447 | for(var i=0; i'; 1482 | gpx+=''+document.getElementById('gpxDesc').value.trim()+''; 1483 | gpx+=''; 1484 | 1485 | document.getElementById('gpxDesc').value=""; 1486 | 1487 | var pathName="Some Name"; 1488 | var pathColour="Blue"; 1489 | var pathLength=roundNumber(this.wkDistance, 3); 1490 | var pathElapsedTime=document.getElementById('elapsedtime').innerHTML; 1491 | var maxSpeed=0; 1492 | for(var i=0; i'; 1510 | gpx+=''+pathColour+''; 1511 | gpx+=''+pathLength+''; 1512 | gpx+=''+pathElapsedTime+''; 1513 | gpx+=''+maxSpeed+''; 1514 | gpx+=''+maxElevation+''; 1515 | gpx+=''+minElevation+''; 1516 | gpx+=''; 1517 | for(var i=0; i'; 1519 | } 1520 | 1521 | gpx+=''; 1522 | download(fileName+".gpx", gpx, 'data:text/xml;charset=utf-8;'); 1523 | 1524 | }, 1525 | 1526 | upload:function(fileContents){ 1527 | this.erase(); 1528 | var dataFile; 1529 | try{ 1530 | dataFile=JSON.parse(fileContents.toString()); 1531 | } 1532 | catch(e){ 1533 | alert("File could not be loaded because it has bad syntax or it's corrupted."); 1534 | return; 1535 | } 1536 | 1537 | if(dataFile.hasOwnProperty('coordinates')){ 1538 | let zm=defaultZoom; 1539 | if(dataFile.hasOwnProperty('zoom')){ 1540 | zm=dataFile['zoom'] 1541 | } 1542 | this.setCoordinates(dataFile['coordinates'].lat, dataFile['coordinates'].lng, zm); 1543 | } 1544 | 1545 | this.head=0; 1546 | if(dataFile.hasOwnProperty('trail')){ 1547 | for(var i=0; i=step){ 1597 | this.speed-=step; 1598 | } 1599 | if(this.speed<=0){ 1600 | this.speed=0.5; 1601 | } 1602 | } 1603 | else{ 1604 | if(this.speed<=this.maxSpeed-step){ 1605 | this.speed+=step; 1606 | } 1607 | else{ 1608 | this.speed=this.maxSpeed; 1609 | } 1610 | } 1611 | document.getElementById('speed').innerHTML=roundNumber(this.speed, 2); 1612 | }, 1613 | 1614 | setSpeed:function(speed){ 1615 | this.speed=Math.abs(speed); 1616 | document.getElementById('speed').innerHTML=roundNumber(this.speed, 2); 1617 | }, 1618 | }; 1619 | 1620 | //#################################################################### 1621 | 1622 | function download(fileName, data, dataType) 1623 | { 1624 | var csvData = data; 1625 | var blob = new Blob([ csvData ], {type : dataType}); 1626 | 1627 | if(window.navigator.msSaveBlob){ 1628 | // FOR IE BROWSER 1629 | navigator.msSaveBlob(blob, fileName); 1630 | } 1631 | else{ 1632 | // FOR OTHER BROWSERS 1633 | var element = document.createElement('a'); 1634 | element.setAttribute('href', URL.createObjectURL(blob)); 1635 | element.setAttribute('download', fileName); 1636 | element.style.display = 'none'; 1637 | document.body.appendChild(element); 1638 | element.click(); 1639 | document.body.removeChild(element); 1640 | } 1641 | popUpAPI.closing(); 1642 | } 1643 | 1644 | //#################################################################### 1645 | 1646 | drawer.init(); 1647 | 1648 | controlModule.setZoom(13.50); 1649 | 1650 | //#################################################################### 1651 | 1652 | window.addEventListener("keydown", function(event){ 1653 | if(event.keyCode==38 || event.keyCode==40){//up=38; down=40 1654 | controlModule.changeAltitude(event.keyCode); 1655 | } 1656 | else if(event.keyCode==37 || event.keyCode==39){//slow=37; fast=39 { 1657 | drawer.changeSpeed(event.keyCode); 1658 | } 1659 | else if(event.keyCode==81 || event.keyCode==87){// q w 1660 | drawer.changeSpeed(event.keyCode); 1661 | } 1662 | else if(event.keyCode==65 || event.keyCode==83){//a s 1663 | drawer.changeSpeed(event.keyCode); 1664 | } 1665 | else if(event.keyCode==88 || event.keyCode==90){ //z x 1666 | drawer.changeSpeed(event.keyCode); 1667 | } 1668 | else { 1669 | //console.log('you pressed: '+event.keyCode); 1670 | } 1671 | }); 1672 | 1673 | document.onkeydown = function(evt) { 1674 | evt = evt || window.event; 1675 | var keyCode = evt.keyCode; 1676 | if (keyCode >= 37 && keyCode <= 40) { 1677 | return false; 1678 | } 1679 | }; 1680 | 1681 | window.addEventListener("DOMContentLoaded", function(){ 1682 | window.scrollTo(0, 0); 1683 | (function(){ 1684 | var dim=document.getElementById('dim'); 1685 | var popUp=document.getElementById('pop_wrapper'); 1686 | var body=document.getElementById('pop_up'); 1687 | var container=document.getElementById('popup_content'); 1688 | 1689 | popUp.style.top=0.1*window.innerHeight+'px'; 1690 | body.style.maxHeight=0.8*window.innerHeight+'px'; 1691 | 1692 | popUpAPI={ 1693 | display:function(){ 1694 | dim.style.display='block'; 1695 | popUp.style.visibility='visible'; 1696 | }, 1697 | closing:function(e){ 1698 | if(typeof e!=='undefined'){ 1699 | e.stopPropagation(); 1700 | return; 1701 | } 1702 | popUp.style.visibility='hidden'; 1703 | dim.style.display='none'; 1704 | document.getElementById('ecef').style.display='none'; 1705 | document.getElementById('rawData').style.display='none'; 1706 | document.getElementById('gpxData').style.display='none'; 1707 | document.getElementById('configuration').style.display='none'; 1708 | document.getElementById('description').style.display='none'; 1709 | //document.getElementById('wait22').style.display='none'; 1710 | }, 1711 | exportECEF:function(){ 1712 | document.getElementById('popup_title').innerHTML='Export to ECEF'; 1713 | document.getElementById('ecef').style.display='block'; 1714 | this.display(); 1715 | }, 1716 | processECEF:function(){ 1717 | var frequency=document.getElementById('frequency'); 1718 | var fileName=document.getElementById('fileName'); 1719 | var x=Number(frequency.value.trim()); 1720 | if(!Number.isInteger(x) || x==0){ 1721 | alert('Please enter a valid integer frequency.'); 1722 | return; 1723 | } 1724 | if(!fileName.value.trim()){ 1725 | alert('Please enter a valid file name.'); 1726 | return; 1727 | } 1728 | popUpAPI.wait(); 1729 | drawer.changeFrequency(x); 1730 | drawer.processData(fileName.value.trim()); 1731 | frequency.value=''; 1732 | fileName.value=''; 1733 | //popUpAPI.closing(); 1734 | }, 1735 | download:function(){ 1736 | document.getElementById('popup_title').innerHTML='Download Path Configuration'; 1737 | document.getElementById('rawData').style.display='block'; 1738 | this.display(); 1739 | }, 1740 | downloadGPX:function(){ 1741 | document.getElementById('popup_title').innerHTML='Download Path GPX'; 1742 | document.getElementById('gpxData').style.display='block'; 1743 | this.display(); 1744 | }, 1745 | settingsECEF:function(){ 1746 | document.getElementById('popup_title').innerHTML='Settings'; 1747 | document.getElementById('configuration').style.display='block'; 1748 | 1749 | this.display(); 1750 | }, 1751 | whatisit:function(){ 1752 | document.getElementById('popup_title').innerHTML='Description'; 1753 | document.getElementById('description').style.display='block'; 1754 | this.display(); 1755 | }, 1756 | wait:function(){ 1757 | document.getElementById('popup_title').innerHTML='Processing data'; 1758 | // document.getElementById('wait22').style.display='block'; 1759 | this.display(); 1760 | }, 1761 | processDownload:function(fileName, id, fileExt){ 1762 | 1763 | if(!fileName.value.trim()){ 1764 | alert('Please enter a valid file name.'); 1765 | return; 1766 | } 1767 | drawer.downloadData(fileName.value.trim(), fileExt); 1768 | fileName.value=''; 1769 | this.closing(); 1770 | document.getElementById(id).style.display='none'; 1771 | }, 1772 | }; 1773 | 1774 | document.getElementById('closePopUp').addEventListener('click', function(){ 1775 | popUpAPI.closing(); 1776 | }); 1777 | 1778 | dim.addEventListener('click', function(){ 1779 | popUpAPI.closing(); 1780 | }); 1781 | 1782 | popUp.addEventListener('click', function(){ 1783 | popUpAPI.closing(); 1784 | }); 1785 | 1786 | container.addEventListener('click', function(event){ 1787 | popUpAPI.closing(event); 1788 | }); 1789 | 1790 | document.getElementById('export').addEventListener('click', function(){ 1791 | popUpAPI.exportECEF(); 1792 | }); 1793 | 1794 | document.getElementById('settings').addEventListener('click', function(){ 1795 | popUpAPI.settingsECEF(); 1796 | }); 1797 | 1798 | document.getElementById('ecefButton').addEventListener('click', function(){ 1799 | popUpAPI.processECEF(); 1800 | }); 1801 | 1802 | document.getElementById('exportData').addEventListener('click', function(){ 1803 | popUpAPI.download(); 1804 | }); 1805 | 1806 | document.getElementById('exportGPX').addEventListener('click', function(){ 1807 | popUpAPI.downloadGPX(); 1808 | }); 1809 | 1810 | document.getElementById('moveToBtn').addEventListener('click', function(){ 1811 | drawer.getPositionFromPointer=!drawer.getPositionFromPointer && drawer.canMove(); 1812 | if(drawer.getPositionFromPointer){ 1813 | document.getElementById('moveToBtn').style.fontWeight="bold"; 1814 | } 1815 | else{ 1816 | document.getElementById('moveToBtn').style.fontWeight="normal"; 1817 | } 1818 | }); 1819 | 1820 | document.getElementById('canvasContainer').addEventListener('mousedown', function(e){ 1821 | if(drawer.getPositionFromPointer){// && drawer.status==0){ 1822 | globalSettings.getPosition3(function(x,y){ 1823 | var latLng=globalSettings.containerPointToLatLng(x, y); 1824 | 1825 | drawer.setCoordinates(latLng.lat, latLng.lng, map.getZoom()); 1826 | 1827 | map.once("moveend", function(){ 1828 | var org=globalSettings.containerCenter(); 1829 | org.add2(-1*x, -1*y); 1830 | Trail.onTranslate(org.x, org.y); 1831 | }.bind(this)); 1832 | }, e); 1833 | } 1834 | }); 1835 | 1836 | document.getElementById('whatisit').addEventListener('click', function(){ 1837 | popUpAPI.whatisit(); 1838 | }); 1839 | 1840 | document.getElementById('rawDataButton').addEventListener('click', function(){ 1841 | popUpAPI.processDownload(document.getElementById('fileNameR'), 'rawData', 'txt'); 1842 | }); 1843 | 1844 | document.getElementById('gpxDataButton').addEventListener('click', function(){ 1845 | popUpAPI.processDownload(document.getElementById('gpxNameR'), 'gpxData', 'gpx'); 1846 | }); 1847 | 1848 | document.getElementById('locationButton').addEventListener('click', function(){ 1849 | var latitude=Number(document.getElementById('latitude').value); 1850 | var longitude=Number(document.getElementById('longitude').value); 1851 | if(Number.isNaN(latitude) || Number.isNaN(longitude)){ 1852 | alert('Please enter a valid number.'); 1853 | return; 1854 | } 1855 | drawer.setCoordinates(latitude, longitude, defaultZoom); 1856 | document.cookie='longitude='+longitude; 1857 | document.cookie='latitude='+latitude; 1858 | }); 1859 | 1860 | document.getElementById('coloursButton').addEventListener('click', function () { 1861 | var trailColour=document.getElementById('trail_colour').value; 1862 | var moverColour=document.getElementById('mover_colour').value; 1863 | trailColour=trailColour.trim(); 1864 | moverColour=moverColour.trim(); 1865 | if(trailColour==''){ 1866 | trailColour="#ffb366"; 1867 | } 1868 | if(moverColour==''){ 1869 | moverColour='blue'; 1870 | } 1871 | Trail.setColours(trailColour, moverColour); 1872 | }); 1873 | 1874 | if(document.cookie==''){ 1875 | //popUpAPI.whatisit(); 1876 | document.cookie="whatisit=yes"; 1877 | } 1878 | 1879 | var latLng=ReadCookie(); 1880 | drawer.setCoordinates(latLng.lat, latLng.lng, defaultZoom); 1881 | 1882 | })(); 1883 | }) 1884 | --------------------------------------------------------------------------------