trail: Fix parsing -- crlf removal is needed.

More documentation, display # points during recovery
Switch to ui library, and start using it.
master
Pavel Machek 2025-07-22 08:24:43 +02:00
parent 9360190b80
commit 401f20514c
2 changed files with 148 additions and 50 deletions

View File

@ -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,6 +493,7 @@ function angleDifference(angle1, angle2) {
return difference; return difference;
} }
/* 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) { function read(pp, n) {
@ -447,13 +517,15 @@ function read(pp, n) {
start = p; start = p;
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), 3, 3);
g.flip(); g.flip();
print(num, "points"); print(num, "points");
@ -467,7 +539,9 @@ function read(pp, n) {
destination = prev; destination = prev;
} }
/* Convert to storagefile, and find out start/stop points (and display some eye-candy) */
function time_read(n) { function time_read(n) {
ui.drawMsg("Converting");
print("Converting..."); print("Converting...");
to_storage(n); to_storage(n);
print("Running..."); print("Running...");
@ -488,6 +562,8 @@ function time_read(n) {
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 +600,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 +634,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 +663,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 +673,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();
@ -626,17 +706,25 @@ function step() {
let quiet = step_to(pp, 1); let quiet = step_to(pp, 1);
if (1) { if (1) {
g.setColor(0, 0, 0); g.setColor(0, 0, 0);
zoom.geoPaint(pp, -pp.course, 500); let zoom_scale = 0;
switch (ui.display) {
case 0: zoom_scale = 500; break;
case 1: zoom_scale = 1500; break;
case 2: zoom_scale = 2500; break;
case 3: /* draw some statistics? */ break;
}
if (zoom_scale)
zoom.geoPaint(pp, -pp.course, 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);
@ -668,6 +756,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 +768,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 +785,11 @@ 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)); ui.drawMsg("Recover\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 +804,6 @@ function to_storage(n) {
} }
} }
ui.init();
fmt.init(); fmt.init();
egt.init(); egt.init();
gps.init(); gps.init();
@ -725,23 +817,27 @@ 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 = 4;
ui.screens = [ "Detail", "Mid", "Overview", "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(x);
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 = () => { ui.drawMsg("Demo mode"); demo_mode = 1; }
ui.topRight = () => { ui.drawMsg("Recover"); recover(); };
} }
/* Display menu with tracks. */
var menu = { var menu = {
"< Back" : Bangle.load "< Back" : Bangle.load
}; };

View File

@ -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 */