2022-07-11 14:51:03 +00:00
|
|
|
|
|
|
|
// screen size is 172x172
|
|
|
|
// we want to show 100 meters ahead
|
|
|
|
// 86 pixels is 100 meters
|
|
|
|
// 10 meters is 8.6 pixels
|
|
|
|
// 1 integer unit is 1.1 meter
|
|
|
|
// 8.6 pixels is 10 / 1.1 integers
|
|
|
|
// int = 8.6 pix * 1.1 / 10
|
|
|
|
// int = 0.946 pixels
|
|
|
|
|
|
|
|
var lat = null;
|
|
|
|
var lon = null;
|
2022-07-12 14:57:34 +00:00
|
|
|
var refresh_needed = false;
|
2022-07-11 14:51:03 +00:00
|
|
|
|
|
|
|
class Path {
|
|
|
|
constructor(filename) {
|
|
|
|
let buffer = require("Storage").readArrayBuffer(filename);
|
2022-07-12 14:45:37 +00:00
|
|
|
this.points = Float64Array(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
point(index) {
|
|
|
|
let lon = this.points[2*index];
|
|
|
|
let lat = this.points[2*index+1];
|
|
|
|
return new Point(lon, lat);
|
|
|
|
}
|
|
|
|
|
|
|
|
// return index of segment which is nearest from point
|
|
|
|
nearest_segment(point, start, end) {
|
|
|
|
let previous_point = null;
|
|
|
|
let min_index = 0;
|
|
|
|
let min_distance = Number.MAX_VALUE;
|
|
|
|
for(let i = Math.max(0, start) ; i < Math.min(this.len, end) ; i++) {
|
|
|
|
let current_point = this.point(i);
|
|
|
|
if (previous_point !== null) {
|
|
|
|
let distance = point.distance_to_segment(previous_point, current_point);
|
|
|
|
if (distance <= min_distance) {
|
|
|
|
min_distance = distance;
|
|
|
|
min_index = i-1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
previous_point = current_point;
|
|
|
|
}
|
|
|
|
return min_index;
|
2022-07-11 14:51:03 +00:00
|
|
|
}
|
|
|
|
get len() {
|
2022-07-12 14:45:37 +00:00
|
|
|
return this.points.length /2;
|
2022-07-11 14:51:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class Point {
|
|
|
|
constructor(lon, lat) {
|
|
|
|
this.lon = lon;
|
|
|
|
this.lat = lat;
|
|
|
|
}
|
|
|
|
screen_x() {
|
2022-07-12 15:01:35 +00:00
|
|
|
return 172/2 + Math.round((this.lon - lon) * 20000.0);
|
2022-07-11 14:51:03 +00:00
|
|
|
}
|
|
|
|
screen_y() {
|
2022-07-12 15:01:35 +00:00
|
|
|
return 172/2 + Math.round((this.lat - lat) * 20000.0);
|
2022-07-12 14:45:37 +00:00
|
|
|
}
|
|
|
|
minus(other_point) {
|
|
|
|
let xdiff = this.lon - other_point.lon;
|
|
|
|
let ydiff = this.lat - other_point.lat;
|
|
|
|
return new Point(xdiff, ydiff);
|
|
|
|
}
|
|
|
|
plus(other_point) {
|
|
|
|
return new Point(this.lon + other_point.lon, this.lat + other_point.lat);
|
|
|
|
}
|
|
|
|
length_squared(other_point) {
|
|
|
|
let d = this.minus(other_point);
|
|
|
|
return (d.lon*d.lon + d.lat*d.lat);
|
|
|
|
}
|
|
|
|
times(scalar) {
|
|
|
|
return new Point(this.lon * scalar, this.lat * scalar);
|
|
|
|
}
|
|
|
|
dot(other_point) {
|
|
|
|
return this.lon * other_point.lon + this.lat * other_point.lat;
|
|
|
|
}
|
|
|
|
distance(other_point) {
|
|
|
|
return Math.sqrt(this.length_squared(other_point));
|
|
|
|
}
|
|
|
|
distance_to_segment(v, w) {
|
|
|
|
// from : https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
|
|
|
|
// Return minimum distance between line segment vw and point p
|
|
|
|
let l2 = v.length_squared(w); // i.e. |w-v|^2 - avoid a sqrt
|
|
|
|
if (l2 == 0.0) {
|
|
|
|
return this.distance(v); // v == w case
|
|
|
|
}
|
|
|
|
// Consider the line extending the segment, parameterized as v + t (w - v).
|
|
|
|
// We find projection of point p onto the line.
|
|
|
|
// It falls where t = [(p-v) . (w-v)] / |w-v|^2
|
|
|
|
// We clamp t from [0,1] to handle points outside the segment vw.
|
|
|
|
let t = Math.max(0, Math.min(1, (this.minus(v)).dot(w.minus(v)) / l2));
|
|
|
|
let projection = v.plus((w.minus(v)).times(t)); // Projection falls on the segment
|
|
|
|
return this.distance(projection);
|
2022-07-11 14:51:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function display(path) {
|
2022-07-12 14:57:34 +00:00
|
|
|
if (!refresh_needed) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
refresh_needed = false;
|
2022-07-11 14:51:03 +00:00
|
|
|
g.clear();
|
2022-07-12 14:45:37 +00:00
|
|
|
g.setColor(g.theme.fg);
|
2022-07-12 14:57:34 +00:00
|
|
|
// let next_segment = path.nearest_segment(new Point(lon, lat), current_segment-2, current_segment+3);
|
|
|
|
current_segment = path.nearest_segment(new Point(lon, lat), 0, path.len);
|
2022-07-11 14:51:03 +00:00
|
|
|
let previous_point = null;
|
2022-07-12 14:57:34 +00:00
|
|
|
let start = Math.max(current_segment - 5, 0);
|
|
|
|
let end = Math.min(current_segment + 7, path.len);
|
2022-07-12 14:45:37 +00:00
|
|
|
for (let i=start ; i < end ; i++) {
|
|
|
|
let point = path.point(i);
|
2022-07-11 14:51:03 +00:00
|
|
|
|
2022-07-12 14:45:37 +00:00
|
|
|
let px = point.screen_x();
|
|
|
|
let py = point.screen_y();
|
2022-07-11 14:51:03 +00:00
|
|
|
if (previous_point !== null) {
|
2022-07-12 14:45:37 +00:00
|
|
|
if (i == current_segment + 1) {
|
|
|
|
g.setColor(0.0, 1.0, 0.0);
|
|
|
|
} else {
|
|
|
|
g.setColor(1.0, 0.0, 0.0);
|
|
|
|
}
|
2022-07-11 14:51:03 +00:00
|
|
|
g.drawLine(
|
|
|
|
previous_point.screen_x(),
|
|
|
|
previous_point.screen_y(),
|
2022-07-12 14:45:37 +00:00
|
|
|
px,
|
|
|
|
py
|
2022-07-11 14:51:03 +00:00
|
|
|
);
|
|
|
|
}
|
2022-07-12 14:45:37 +00:00
|
|
|
g.setColor(g.theme.fg2);
|
|
|
|
g.fillCircle(px, py, 4);
|
|
|
|
g.setColor(g.theme.fg);
|
|
|
|
g.fillCircle(px, py, 3);
|
2022-07-11 14:51:03 +00:00
|
|
|
previous_point = point;
|
|
|
|
}
|
2022-07-12 14:45:37 +00:00
|
|
|
g.setColor(g.theme.fgH);
|
|
|
|
g.fillCircle(172/2, 172/2, 5);
|
2022-07-12 14:57:34 +00:00
|
|
|
Bangle.drawWidgets();
|
2022-07-11 14:51:03 +00:00
|
|
|
}
|
|
|
|
|
2022-07-12 18:07:25 +00:00
|
|
|
Bangle.loadWidgets();
|
2022-07-11 14:51:03 +00:00
|
|
|
let path = new Path("test.gpc");
|
2022-07-12 14:45:37 +00:00
|
|
|
var current_segment = path.nearest_segment(new Point(lon, lat), 0, Number.MAX_VALUE);
|
2022-07-11 14:51:03 +00:00
|
|
|
|
2022-07-12 14:57:34 +00:00
|
|
|
|
|
|
|
// let fake_gps_point = 0.0;
|
|
|
|
// function simulate_gps(path) {
|
|
|
|
// let point_index = Math.floor(fake_gps_point);
|
|
|
|
// if (point_index >= path.len) {
|
|
|
|
// return;
|
2022-07-12 14:45:37 +00:00
|
|
|
// }
|
2022-07-12 14:57:34 +00:00
|
|
|
// let p1 = path.point(point_index);
|
|
|
|
// let p2 = path.point(point_index+1);
|
|
|
|
// let alpha = fake_gps_point - point_index;
|
|
|
|
|
|
|
|
// lon = (1-alpha)*p1.lon + alpha*p2.lon;
|
|
|
|
// lat = (1-alpha)*p1.lat + alpha*p2.lat;
|
|
|
|
// fake_gps_point += 0.2;
|
|
|
|
// display(path);
|
2022-07-12 14:45:37 +00:00
|
|
|
// }
|
|
|
|
|
2022-07-12 14:57:34 +00:00
|
|
|
// setInterval(simulate_gps, 500, path);
|
2022-07-12 14:45:37 +00:00
|
|
|
|
|
|
|
|
2022-07-12 14:57:34 +00:00
|
|
|
function set_coordinates(data) {
|
|
|
|
let old_lat = lat;
|
|
|
|
if (!isNaN(data.lat)) {
|
|
|
|
lat = data.lat;
|
|
|
|
}
|
|
|
|
let old_lon = lon;
|
|
|
|
if (!isNaN(data.lon)) {
|
|
|
|
lon = data.lon;
|
|
|
|
}
|
|
|
|
if ((old_lat != lat)||(old_lon != lon)) {
|
|
|
|
refresh_needed = true;
|
2022-07-11 14:51:03 +00:00
|
|
|
}
|
2022-07-12 14:45:37 +00:00
|
|
|
}
|
2022-07-12 14:57:34 +00:00
|
|
|
Bangle.setGPSPower(true, "gipy");
|
|
|
|
Bangle.on('GPS', set_coordinates);
|
|
|
|
|
2022-07-11 14:51:03 +00:00
|
|
|
|
2022-07-12 14:57:34 +00:00
|
|
|
setInterval(display, 1000, path);
|
2022-07-11 14:51:03 +00:00
|
|
|
|