Merge pull request #3949 from pavelmachek/m_51_trail
trail 0.20: allow drawing map around current locationmaster
commit
0c394edb6d
|
|
@ -1,4 +1,4 @@
|
||||||
0.01: New App!
|
0.01: New App!
|
||||||
0.10: Redesign to make screen updates fast
|
0.10: Redesign to make screen updates fast
|
||||||
0.11: bugfix (demo mode was enabled by default)
|
0.11: bugfix (demo mode was enabled by default)
|
||||||
|
0.20: Add screen with map around current position
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,27 @@ After GPS fix is acquired, it displays familiar arrow with road in
|
||||||
front of you. It never stores whole track in memory, so it should work
|
front of you. It never stores whole track in memory, so it should work
|
||||||
with fairly large files.
|
with fairly large files.
|
||||||
|
|
||||||
GPX files can be obtained from various services, www.mapy.cz is one of
|
On startup, you select track you want to work with. After it is
|
||||||
them (actually uses openstreetmap data for most of the world).
|
loaded, few screens are available.
|
||||||
|
|
||||||
|
1) "Follow" -- displays arrow on the track. Should work well as you
|
||||||
|
follow the route. If you get lost, press top right corner to "recover".
|
||||||
|
|
||||||
|
2) "Map" -- can draw a track around your current position. Press top
|
||||||
|
right corner to redraw.
|
||||||
|
|
||||||
|
3) "Statistics"
|
||||||
|
|
||||||
|
Press touchscreen corners to select functions
|
||||||
|
|
||||||
|
Zoom Function
|
||||||
|
Prev screen Next
|
||||||
|
|
||||||
## Preparing data
|
## Preparing data
|
||||||
|
|
||||||
"gpx2egt.sh < file.gpx > t.name.egt" can be used to prepare data, then
|
GPX files can be obtained from various services, www.mapy.cz is one of
|
||||||
upload it to watch.
|
them (actually uses openstreetmap data for most of the world).
|
||||||
|
|
||||||
# [rt].*.egt
|
"gpx2egt.sh < file.gpx > t.name.egt" can be used to prepare data, then
|
||||||
# deal with "end of trail"
|
upload it to watch. Filename has to be in t.*.egt or r.*.egt format
|
||||||
|
(suggestion is to use t.* for track "there" and r.* for return track).
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{ "id": "trail",
|
{ "id": "trail",
|
||||||
"name": "Trail Rail",
|
"name": "Trail Rail",
|
||||||
"version":"0.11",
|
"version":"0.20",
|
||||||
"description": "Follow a GPX track in car or on bike",
|
"description": "Follow a GPX track in car or on bike",
|
||||||
"icon": "app.png",
|
"icon": "app.png",
|
||||||
"readme": "README.md",
|
"readme": "README.md",
|
||||||
|
|
|
||||||
|
|
@ -181,42 +181,72 @@ let gps = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ui library 0.1.2 */
|
/* ui library 0.2.0 -- see skyspy */
|
||||||
|
//Bangle.on("drag", (b) => ui.touchHandler(b));
|
||||||
let ui = {
|
let ui = {
|
||||||
display: 0,
|
display: 0,
|
||||||
numScreens: 2,
|
numScreens: 2,
|
||||||
|
name: ".oO busy",
|
||||||
|
screens: [ "Screen 1", "Screen 2", "Screen 3", "Screen 4", "Screen 5", "Screen 6" ],
|
||||||
|
help: [ "F1", "F2", "<", ">" ],
|
||||||
|
clear: function() {
|
||||||
|
g.reset()
|
||||||
|
.setColor(g.theme.bg)
|
||||||
|
.fillRect(0, this.wi, this.w, this.y2)
|
||||||
|
.setColor(g.theme.fg);
|
||||||
|
},
|
||||||
|
draw: function(screen) {},
|
||||||
drawMsg: function(msg) {
|
drawMsg: function(msg) {
|
||||||
g.reset().setFont("Vector", 35)
|
this.clear();
|
||||||
.setColor(1,1,1)
|
g.setFont("Vector", 35)
|
||||||
.fillRect(0, this.wi, 176, 176)
|
|
||||||
.setColor(0,0,0)
|
|
||||||
.drawString(msg, 5, 30)
|
.drawString(msg, 5, 30)
|
||||||
.flip();
|
.flip();
|
||||||
},
|
},
|
||||||
drawBusy: function() {
|
drawBusy: function() {
|
||||||
this.drawMsg("\n.oO busy");
|
this.clear();
|
||||||
|
g.setFont("Vector", 35);
|
||||||
|
let help = this.help;
|
||||||
|
g.setFontAlign(-1, -1).drawString(help[0], 0, this.wi);
|
||||||
|
g.setFontAlign(1, -1).drawString(help[1], this.w, this.wi);
|
||||||
|
g.setFontAlign(-1, 1).drawString(help[2], 0, this.h+this.wi);
|
||||||
|
g.setFontAlign(1, 1).drawString(help[3], this.w, this.h+this.wi);
|
||||||
|
g.setFontAlign(0, 0)
|
||||||
|
.drawString(this.name, this.w/2, this.h/2);
|
||||||
|
g.reset();
|
||||||
|
},
|
||||||
|
drawScreen: function() {
|
||||||
|
this.drawMsg(this.screens[this.display]);
|
||||||
|
let t1 = getTime();
|
||||||
|
this.draw();
|
||||||
|
let t = getTime() - t1;
|
||||||
|
if (t > 30) {
|
||||||
|
print("Draw took", t, "msec");
|
||||||
|
}
|
||||||
},
|
},
|
||||||
nextScreen: function() {
|
nextScreen: function() {
|
||||||
print("nextS");
|
print("nextS");
|
||||||
this.display = this.display + 1;
|
this.display = this.display + 1;
|
||||||
if (this.display == this.numScreens)
|
if (this.display == this.numScreens)
|
||||||
this.display = 0;
|
this.display = 0;
|
||||||
this.drawBusy();
|
this.drawScreen();
|
||||||
},
|
},
|
||||||
prevScreen: function() {
|
prevScreen: function() {
|
||||||
print("prevS");
|
print("prevS");
|
||||||
this.display = this.display - 1;
|
this.display = this.display - 1;
|
||||||
if (this.display < 0)
|
if (this.display < 0)
|
||||||
this.display = this.numScreens - 1;
|
this.display = this.numScreens - 1;
|
||||||
this.drawBusy();
|
this.drawScreen();
|
||||||
},
|
},
|
||||||
onSwipe: function(dir) {
|
onSwipe: function(dir) {
|
||||||
this.nextScreen();
|
this.nextScreen();
|
||||||
},
|
},
|
||||||
h: 176,
|
wi: 24,
|
||||||
|
y2: 176,
|
||||||
|
h: 152,
|
||||||
w: 176,
|
w: 176,
|
||||||
wi: 32,
|
|
||||||
last_b: 0,
|
last_b: 0,
|
||||||
|
topLeft: function() { this.drawMsg("Unimpl"); },
|
||||||
|
topRight: function() { this.drawMsg("Unimpl"); },
|
||||||
touchHandler: function(d) {
|
touchHandler: function(d) {
|
||||||
let x = Math.floor(d.x);
|
let x = Math.floor(d.x);
|
||||||
let y = Math.floor(d.y);
|
let y = Math.floor(d.y);
|
||||||
|
|
@ -228,46 +258,85 @@ let ui = {
|
||||||
|
|
||||||
print("touch", x, y, this.h, this.w);
|
print("touch", x, y, this.h, this.w);
|
||||||
|
|
||||||
/*
|
if ((x<this.w/2) && (y<this.y2/2))
|
||||||
if ((x<this.h/2) && (y<this.w/2)) {
|
this.topLeft();
|
||||||
}
|
if ((x>this.w/2) && (y<this.y2/2))
|
||||||
if ((x>this.h/2) && (y<this.w/2)) {
|
this.topRight();
|
||||||
}
|
if ((x<this.w/2) && (y>this.y2/2)) {
|
||||||
*/
|
|
||||||
|
|
||||||
if ((x<this.h/2) && (y>this.w/2)) {
|
|
||||||
print("prev");
|
print("prev");
|
||||||
this.prevScreen();
|
this.prevScreen();
|
||||||
}
|
}
|
||||||
if ((x>this.h/2) && (y>this.w/2)) {
|
if ((x>this.w/2) && (y>this.y2/2)) {
|
||||||
print("next");
|
print("next");
|
||||||
this.nextScreen();
|
this.nextScreen();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
init: function() {
|
init: function() {
|
||||||
|
this.h = this.y2 - this.wi;
|
||||||
this.drawBusy();
|
this.drawBusy();
|
||||||
}
|
},
|
||||||
|
/* radial angle -- convert 0..1 to 0..2pi */
|
||||||
|
radA: function(p) { return p*(Math.PI*2); },
|
||||||
|
/* radial distance -- convert 0..1 to something that fits on screen */
|
||||||
|
radD: function(d) { return d*(ui.h/2); },
|
||||||
|
|
||||||
|
/* given angle/distance, get X coordinate */
|
||||||
|
radX: function(p, d) {
|
||||||
|
let a = this.radA(p);
|
||||||
|
return this.w/2 + Math.sin(a)*this.radD(d);
|
||||||
|
},
|
||||||
|
/* given angle/distance, get Y coordinate */
|
||||||
|
radY: function(p, d) {
|
||||||
|
let a = this.radA(p);
|
||||||
|
return this.h/2 - Math.cos(a)*this.radD(d) + this.wi;
|
||||||
|
},
|
||||||
|
radLine: function(a1, d1, a2, d2) {
|
||||||
|
g.drawLine(this.radX(a1, d1), this.radY(a1, d1), this.radX(a2, d2), this.radY(a2, d2));
|
||||||
|
},
|
||||||
|
radCircle: function(d) {
|
||||||
|
g.drawCircle(this.radX(0, 0), this.radY(0, 0), this.radD(d));
|
||||||
|
if (1)
|
||||||
|
return;
|
||||||
|
let step = 0.05;
|
||||||
|
for (let i = 0; i < 1; i += 0.05) {
|
||||||
|
this.radLine(i - step, d, i, d);
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* egt 0.0.1 */
|
/* egt 0.0.3 */
|
||||||
let egt = {
|
let egt = {
|
||||||
init: function() {
|
init: function() {
|
||||||
},
|
},
|
||||||
|
removeCRLF: function(s) {
|
||||||
|
let end = s.length;
|
||||||
|
while (end > 0) {
|
||||||
|
let ch = s[end - 1];
|
||||||
|
if (ch === '\n' || ch === '\r') {
|
||||||
|
end--;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s.slice(0, end);
|
||||||
|
},
|
||||||
|
|
||||||
parse: function(l) {
|
parse: function(l) {
|
||||||
|
l = this.removeCRLF(l);
|
||||||
let r = {};
|
let r = {};
|
||||||
let s = l.split(' ');
|
let s = l.split(' ');
|
||||||
|
|
||||||
if (s === undefined)
|
if (s === undefined)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (s[1] === undefined)
|
if (s[1] === undefined)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
if (s[1].split('=')[1] === undefined) {
|
if (s[1].split('=')[1] === undefined) {
|
||||||
r.lat = 1 * s[0];
|
r.lat = 1 * s[0];
|
||||||
r.lon = 1 * s[1];
|
r.lon = 1 * s[1];
|
||||||
if (!r.lat || !r.lon) {
|
if (!r.lat || !r.lon) {
|
||||||
print("Parse error at ", l);
|
print("Parse error at ", l, "have (", s[0], s[1], ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -282,6 +351,7 @@ let egt = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/* zoom library v0.0.4 */
|
/* zoom library v0.0.4 */
|
||||||
var zoom = {
|
var zoom = {
|
||||||
buf : 0,
|
buf : 0,
|
||||||
|
|
@ -367,9 +437,8 @@ var zoom = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
function toCartesian(v) {
|
function toCartesian(v) {
|
||||||
const R = 6371; // Poloměr Země v km
|
const R = 6371; // Earth radius in km
|
||||||
const latRad = v.lat * Math.PI / 180;
|
const latRad = v.lat * Math.PI / 180;
|
||||||
const lonRad = v.lon * Math.PI / 180;
|
const lonRad = v.lon * Math.PI / 180;
|
||||||
|
|
||||||
|
|
@ -424,9 +493,13 @@ function angleDifference(angle1, angle2) {
|
||||||
return difference;
|
return difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Main code */
|
||||||
|
|
||||||
|
/* These are initialized by read() function, below */
|
||||||
var start = {}, destination = {}, num = 0, dist = 0;
|
var start = {}, destination = {}, num = 0, dist = 0;
|
||||||
|
|
||||||
function read(pp, n) {
|
/* pp .. Point, n .. filename, candy .. enable "eye candy" drawing */
|
||||||
|
function read(pp, n, candy) {
|
||||||
let f = require("Storage").open(n+".st", "r");
|
let f = require("Storage").open(n+".st", "r");
|
||||||
let l = f.readLine();
|
let l = f.readLine();
|
||||||
let prev = 0;
|
let prev = 0;
|
||||||
|
|
@ -443,21 +516,26 @@ function read(pp, n) {
|
||||||
if (pp.g)
|
if (pp.g)
|
||||||
paint(pp, prev, p, 1);
|
paint(pp, prev, p, 1);
|
||||||
} else {
|
} else {
|
||||||
zoom.geoNew(p, 3000);
|
if (candy)
|
||||||
|
zoom.geoNew(p, 3000);
|
||||||
start = p;
|
start = p;
|
||||||
|
if (candy) {
|
||||||
pp.lat = p.lat;
|
pp.lat = p.lat;
|
||||||
pp.lon = p.lon;
|
pp.lon = p.lon;
|
||||||
|
}
|
||||||
|
/* FIXME: won't init destination */
|
||||||
|
//return;
|
||||||
}
|
}
|
||||||
prev = p;
|
prev = p;
|
||||||
}
|
}
|
||||||
l = f.readLine();
|
l = f.readLine();
|
||||||
if (!(num % 30)) {
|
if (!(num % 30)) {
|
||||||
g.clear();
|
g.clear();
|
||||||
zoom.geoPaint(prev, 0, 1500);
|
zoom.geoPaint(prev, 0, 2500);
|
||||||
g.drawString(num + "\n" + fmt.fmtDist(dist / 1000), 3, 3);
|
g.drawString(num + "\n" + fmt.fmtDist(dist / 1000) + "\n" + track_name, 3, 3);
|
||||||
g.flip();
|
g.flip();
|
||||||
print(num, "points");
|
print(num, "points");
|
||||||
if (!(num % 300)) {
|
if (candy && !(num % 300)) {
|
||||||
zoom.geoNew(prev, 3000);
|
zoom.geoNew(prev, 3000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -467,7 +545,10 @@ function read(pp, n) {
|
||||||
destination = prev;
|
destination = prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
function time_read(n) {
|
/* Find out start/stop points (and display some eye-candy) */
|
||||||
|
function time_read() {
|
||||||
|
let n = track_name;
|
||||||
|
ui.drawMsg("Converting");
|
||||||
print("Converting...");
|
print("Converting...");
|
||||||
to_storage(n);
|
to_storage(n);
|
||||||
print("Running...");
|
print("Running...");
|
||||||
|
|
@ -478,16 +559,19 @@ function time_read(n) {
|
||||||
pp.x = 176/2;
|
pp.x = 176/2;
|
||||||
pp.y = 176/2;
|
pp.y = 176/2;
|
||||||
pp.g = zoom.buf;
|
pp.g = zoom.buf;
|
||||||
read(pp, n);
|
read(pp, n, 1);
|
||||||
// { rotate: Math.PI / 4 + i/100, scale: 1-i/100 }
|
// { rotate: Math.PI / 4 + i/100, scale: 1-i/100 }
|
||||||
|
|
||||||
let v2 = getTime();
|
let v2 = getTime();
|
||||||
print("Read took", (v2-v1), "seconds");
|
print("Read took", (v2-v1), "seconds");
|
||||||
step_init();
|
step_init();
|
||||||
|
zoom.geoNew(start, 3000);
|
||||||
print(num, "points", dist, "distance");
|
print(num, "points", dist, "distance");
|
||||||
setTimeout(step, 100);
|
setTimeout(step, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Main code for displaying track */
|
||||||
|
|
||||||
var track_name = "", inf, point_num, track = [], track_points = 30, north = {}, point_drawn;
|
var track_name = "", inf, point_num, track = [], track_points = 30, north = {}, point_drawn;
|
||||||
|
|
||||||
function step_init() {
|
function step_init() {
|
||||||
|
|
@ -524,6 +608,7 @@ function paint(pp, p1, p2, thick) {
|
||||||
zoom.geoLine(p1, p2);
|
zoom.geoLine(p1, p2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Paint points in window around current position */
|
||||||
function paint_all(pp) {
|
function paint_all(pp) {
|
||||||
let prev = 0;
|
let prev = 0;
|
||||||
let mDist = 99999999999, m = 0;
|
let mDist = 99999999999, m = 0;
|
||||||
|
|
@ -557,10 +642,13 @@ function paint_all(pp) {
|
||||||
if (fast)
|
if (fast)
|
||||||
return { quiet: 0, offtrack : 0 };
|
return { quiet: 0, offtrack : 0 };
|
||||||
print("Best segment was", m, "dist", mDist);
|
print("Best segment was", m, "dist", mDist);
|
||||||
if (fmt.distance(track[m], zoom.origin) > 1500) {
|
/* If we are too far from ... */
|
||||||
|
if (fmt.distance(track[m], zoom.origin) > 2500) {
|
||||||
zoom.geoNew(track[m], 3000); // FIXME: this will flicker
|
zoom.geoNew(track[m], 3000); // FIXME: this will flicker
|
||||||
point_drawn = 0;
|
point_drawn = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Estimate distance to next turn/intersection */
|
||||||
let ahead = 0, a = fmt.bearing(track[m-1], track[m]), quiet = -1;
|
let ahead = 0, a = fmt.bearing(track[m-1], track[m]), quiet = -1;
|
||||||
for (let i = m+1; i < track.length; i++) {
|
for (let i = m+1; i < track.length; i++) {
|
||||||
let a2 = fmt.bearing(track[i-1], track[i]);
|
let a2 = fmt.bearing(track[i-1], track[i]);
|
||||||
|
|
@ -583,6 +671,8 @@ function drop_last() {
|
||||||
track.shift();
|
track.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Display data for given position -- pp.
|
||||||
|
Drop data that are more than 150 meters behind current position */
|
||||||
function step_to(pp, pass_all) {
|
function step_to(pp, pass_all) {
|
||||||
if (0) {
|
if (0) {
|
||||||
g.setColor(0.5, 0.5, 1);
|
g.setColor(0.5, 0.5, 1);
|
||||||
|
|
@ -591,9 +681,7 @@ function step_to(pp, pass_all) {
|
||||||
g.setColor(1, 0.5, 0.5);
|
g.setColor(1, 0.5, 0.5);
|
||||||
paint(pp, pp, north, 1);
|
paint(pp, pp, north, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let quiet = paint_all(pp);
|
let quiet = paint_all(pp);
|
||||||
|
|
||||||
while (distSegment(track[0], track[1], pp) > 150 &&
|
while (distSegment(track[0], track[1], pp) > 150 &&
|
||||||
track.length > 10) {
|
track.length > 10) {
|
||||||
drop_last();
|
drop_last();
|
||||||
|
|
@ -601,46 +689,75 @@ function step_to(pp, pass_all) {
|
||||||
return quiet;
|
return quiet;
|
||||||
}
|
}
|
||||||
|
|
||||||
var demo_mode = 0;
|
var demo_mode = 0, zoom_mode = 0;
|
||||||
|
|
||||||
function step() {
|
function step() {
|
||||||
const fast = 0;
|
const fast = 0;
|
||||||
|
let follow = 0;
|
||||||
|
switch (ui.display) {
|
||||||
|
case 0: follow = 1; break;
|
||||||
|
case 1: break;
|
||||||
|
case 2: follow = 1; break;
|
||||||
|
}
|
||||||
|
|
||||||
let v1 = getTime();
|
let v1 = getTime();
|
||||||
g.reset().clear();
|
g.reset().clear();
|
||||||
|
|
||||||
let fix = gps.getGPSFix();
|
let fix = gps.getGPSFix();
|
||||||
|
let have_more = 1;
|
||||||
let have_more = load_next();
|
if (follow)
|
||||||
|
have_more = load_next();
|
||||||
|
|
||||||
let pp = fix;
|
let pp = fix;
|
||||||
pp.ppm = 0.08 * 3; /* Pixels per meter */
|
pp.ppm = 0.08 * 3; /* Pixels per meter */
|
||||||
pp.g = g;
|
pp.g = g;
|
||||||
|
|
||||||
if (demo_mode || !fix.fix) {
|
if (follow && (demo_mode || !fix.fix)) {
|
||||||
let i = 2;
|
let i = 2;
|
||||||
pp.lat = track[i].lat;
|
pp.lat = track[i].lat;
|
||||||
pp.lon = track[i].lon;
|
pp.lon = track[i].lon;
|
||||||
pp.course = fmt.bearing(track[i], track[i+1]);
|
pp.course = fmt.bearing(track[i], track[i+1]);
|
||||||
}
|
}
|
||||||
|
if (!follow && !fix.fix) {
|
||||||
|
pp.lat = 50.010507; /* FIXME */
|
||||||
|
pp.lon = 14.765840;
|
||||||
|
pp.course = 0;
|
||||||
|
}
|
||||||
|
|
||||||
let quiet = step_to(pp, 1);
|
let quiet = {};
|
||||||
if (1) {
|
if (follow)
|
||||||
|
quiet = step_to(pp, 1);
|
||||||
|
let zoom_scale = 0;
|
||||||
|
switch (zoom_mode) {
|
||||||
|
case 0: zoom_scale = 500; break;
|
||||||
|
case 1: zoom_scale = 1500; break;
|
||||||
|
case 2: zoom_scale = 2500; break;
|
||||||
|
}
|
||||||
|
switch (ui.display) {
|
||||||
|
case 0: break;
|
||||||
|
case 1: break;
|
||||||
|
case 2:
|
||||||
|
ui.drawMsg("Stats\n" + fmt.fmtDist(0 / 1000) + "\n" + point_num + "/" + num);
|
||||||
|
zoom_scale = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (zoom_scale) {
|
||||||
g.setColor(0, 0, 0);
|
g.setColor(0, 0, 0);
|
||||||
zoom.geoPaint(pp, -pp.course, 500);
|
zoom.geoPaint(pp, -pp.course, zoom_scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (zoom_scale) {
|
||||||
pp.x = ui.w/2;
|
/* Draw arrow representing current position */
|
||||||
pp.y = ui.h*0.5;
|
pp.x = ui.w/2;
|
||||||
|
pp.y = ui.h*0.5;
|
||||||
g.setColor(0, 0, 1);
|
|
||||||
let sc = 2.5;
|
|
||||||
g.drawPoly([ pp.x, pp.y, pp.x - 5*sc, pp.y + 12*sc, pp.x + 5*sc, pp.y + 12*sc ], true);
|
|
||||||
|
|
||||||
|
g.setColor(0, 0, 1);
|
||||||
|
let sc = 2.5;
|
||||||
|
g.drawPoly([ pp.x, pp.y, pp.x - 5*sc, pp.y + 12*sc, pp.x + 5*sc, pp.y + 12*sc ], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
g.setColor(0, 0, 0);
|
g.setColor(0, 0, 0);
|
||||||
if (!fast) {
|
if (zoom_scale && !fast) {
|
||||||
g.setFont("Vector", 31);
|
g.setFont("Vector", 31);
|
||||||
g.setFontAlign(-1, -1);
|
g.setFontAlign(-1, -1);
|
||||||
let msg = "\noff " + fmt.fmtDist(quiet.offtrack/1000);
|
let msg = "\noff " + fmt.fmtDist(quiet.offtrack/1000);
|
||||||
|
|
@ -649,7 +766,7 @@ function step() {
|
||||||
}
|
}
|
||||||
g.drawString(fmt.fmtFix(fix, getTime()-gps.gps_start) + msg, 3, 3);
|
g.drawString(fmt.fmtFix(fix, getTime()-gps.gps_start) + msg, 3, 3);
|
||||||
}
|
}
|
||||||
if (!fast) {
|
if (zoom_scale && !fast) {
|
||||||
g.setFont("Vector", 23);
|
g.setFont("Vector", 23);
|
||||||
g.setColor(0, 0, 0);
|
g.setColor(0, 0, 0);
|
||||||
g.setFontAlign(-1, 1);
|
g.setFontAlign(-1, 1);
|
||||||
|
|
@ -668,6 +785,10 @@ function step() {
|
||||||
setTimeout(step, 1000);
|
setTimeout(step, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Recovery: If we get completely lost, we can do this.
|
||||||
|
It works similar to main loop, but faster.
|
||||||
|
It simply drop points until we are 400meters from the fix, then main code can take over.
|
||||||
|
*/
|
||||||
function recover() {
|
function recover() {
|
||||||
ui.drawMsg("Recover...");
|
ui.drawMsg("Recover...");
|
||||||
step_init();
|
step_init();
|
||||||
|
|
@ -676,7 +797,7 @@ function recover() {
|
||||||
pp.ppm = 0.08 * 3; /* Pixels per meter */
|
pp.ppm = 0.08 * 3; /* Pixels per meter */
|
||||||
if (!fix.fix) {
|
if (!fix.fix) {
|
||||||
print("Can't recover with no fix\n");
|
print("Can't recover with no fix\n");
|
||||||
fix.lat = 50.010507;
|
fix.lat = 50.010507; /* FIXME */
|
||||||
fix.lon = 14.765840;
|
fix.lon = 14.765840;
|
||||||
}
|
}
|
||||||
load_next();
|
load_next();
|
||||||
|
|
@ -693,10 +814,33 @@ function recover() {
|
||||||
step_to(pp, 1);
|
step_to(pp, 1);
|
||||||
if (!load_next())
|
if (!load_next())
|
||||||
break;
|
break;
|
||||||
ui.drawMsg("Recover\n" + fmt.fmtDist(d / 1000));
|
if (!(point_num % 30))
|
||||||
|
ui.drawMsg("Recover\n" + fmt.fmtDist(d / 1000) + "\n" + point_num + "/" + num + "\n" + track_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Draw map around current position */
|
||||||
|
function draw_map() {
|
||||||
|
ui.drawMsg("Draw...");
|
||||||
|
let fix = gps.getGPSFix();
|
||||||
|
if (!fix.fix) {
|
||||||
|
print("Can't draw with no fix\n");
|
||||||
|
fix.lat = 50.010507; /* FIXME */
|
||||||
|
fix.lon = 14.765840;
|
||||||
|
}
|
||||||
|
let pp = fix;
|
||||||
|
pp.ppm = 0.008 * 5; /* Pixels per meter */
|
||||||
|
pp.course = 0;
|
||||||
|
pp.x = 176/2;
|
||||||
|
pp.y = 176/2;
|
||||||
|
pp.g = zoom.buf;
|
||||||
|
let d = 0;
|
||||||
|
step_init();
|
||||||
|
read(pp, track_name, 0);
|
||||||
|
ui.drawMsg("Drawn\n" + fmt.fmtDist(d / 1000) + "\n" + point_num + "/" + num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert "normal" file to storagefile... so that we can read lines from it */
|
||||||
function to_storage(n) {
|
function to_storage(n) {
|
||||||
let f2 = require("Storage").open(n+".st", "w");
|
let f2 = require("Storage").open(n+".st", "w");
|
||||||
let pos = 0;
|
let pos = 0;
|
||||||
|
|
@ -711,7 +855,6 @@ function to_storage(n) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.init();
|
|
||||||
fmt.init();
|
fmt.init();
|
||||||
egt.init();
|
egt.init();
|
||||||
gps.init();
|
gps.init();
|
||||||
|
|
@ -725,23 +868,45 @@ l = st.list(l, {sf:false});
|
||||||
|
|
||||||
print(l);
|
print(l);
|
||||||
|
|
||||||
|
/* After user selected the track, we can switch to main interface */
|
||||||
function load_track(x) {
|
function load_track(x) {
|
||||||
|
ui.init();
|
||||||
|
ui.numScreens = 3;
|
||||||
|
ui.screens = [ "Follow", "Map", "Stats" ];
|
||||||
|
|
||||||
Bangle.buzz(50, 1);
|
Bangle.buzz(50, 1);
|
||||||
ui.drawMsg("Loading\n"+x);
|
ui.drawMsg("Loading\n"+x);
|
||||||
track_name = x;
|
track_name = x;
|
||||||
time_read(x);
|
time_read();
|
||||||
|
|
||||||
Bangle.setUI("clockupdown", btn => {
|
Bangle.on("drag", (b) => ui.touchHandler(b));
|
||||||
print("Button", btn);
|
Bangle.setUI({
|
||||||
if (btn == -1) {
|
mode : "custom",
|
||||||
recover();
|
clock : 0
|
||||||
}
|
|
||||||
if (btn == 1) {
|
|
||||||
demo_mode = 1;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
ui.topLeft = () => {
|
||||||
|
switch (ui.display) {
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
zoom_mode++;
|
||||||
|
if (zoom_mode == 3)
|
||||||
|
zoom_mode = 0;
|
||||||
|
ui.drawMsg("Zoom\nmode\n" + zoom_mode);
|
||||||
|
break;
|
||||||
|
case 2: demo_mode = !demo_mode;
|
||||||
|
ui.drawMsg("Demo\nmode\n" + demo_mode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui.topRight = () => {
|
||||||
|
switch (ui.display) {
|
||||||
|
case 0: ui.drawMsg("Recover"); recover(); break;
|
||||||
|
case 1: ui.drawMsg("Draw map"); draw_map(); break;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Display menu with tracks. */
|
||||||
var menu = {
|
var menu = {
|
||||||
"< Back" : Bangle.load
|
"< Back" : Bangle.load
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
/* Thanks to pinsafe from BangleApps repository */
|
/* Thanks to pinsafe from BangleApps repository */
|
||||||
|
|
||||||
|
/* create waypoint is unusable on watch -- button takes us back to menu */
|
||||||
|
|
||||||
var Layout = require("Layout");
|
var Layout = require("Layout");
|
||||||
|
|
||||||
/* fmt library v0.2.3 */
|
/* fmt library v0.2.3 */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue