gipy: fixed perf issues in new display algorithm

master
frederic wagner 2023-11-20 11:48:45 +01:00
parent 4da1282dec
commit bd3f4489c4
3 changed files with 141 additions and 135 deletions

View File

@ -117,7 +117,8 @@
* Bugfix in nearest segment detection * Bugfix in nearest segment detection
0.23: 0.23:
* New display algorithm : way faster, larger roads * New display algorithm : way faster, larger roads, zooming out is now ok
* You will need to re-generate your maps because the new algorithm uses a different scale
* Better path simplification * Better path simplification
* Waypoints autodetection using the map * Waypoints autodetection using the map
* New option: sleep between waypoints * New option: sleep between waypoints

View File

@ -1,6 +1,7 @@
urgent TODO: urgent TODO:
- prefetch tiles ?
- update documentation to reflect new display ? - update documentation to reflect new display ?
- add an image for the arrow ? - add an image for the arrow ?

View File

@ -152,29 +152,8 @@ class TilesOffsets {
} }
} }
// this function is not inlined to avoid array declaration in jit
function center_points(points, scaled_current_x, scaled_current_y) {
return g.transformVertices(points, [
1,
0,
0,
1,
-scaled_current_x,
-scaled_current_y,
]);
}
// this function is not inlined to avoid array declaration in jit
function rotate_points(points, c, s) {
let center_x = g.getWidth() / 2;
let center_y = g.getHeight() / 2 + Y_OFFSET;
return g.transformVertices(points, [-c, s, s, c, center_x, center_y]);
}
class Map { class Map {
constructor(buffer, offset, filename) { constructor(buffer, offset, filename) {
this.points_cache = []; // don't refetch points all the time
// header // header
let color_array = Uint8Array(buffer, offset, 3); let color_array = Uint8Array(buffer, offset, 3);
this.color = [ this.color = [
@ -338,7 +317,6 @@ class Interests {
this.binary_interests[i] = binary_interests[i]; this.binary_interests[i] = binary_interests[i];
} }
offset += end; offset += end;
this.points_cache = [];
return [this, offset]; return [this, offset];
} }
@ -388,7 +366,7 @@ class Status {
this.reaching = null; // which waypoint are we reaching ? this.reaching = null; // which waypoint are we reaching ?
this.distance_to_next_point = null; // how far are we from next point ? this.distance_to_next_point = null; // how far are we from next point ?
this.projected_point = null; this.projected_point = null;
this.images_cache = []; this.reset_images_cache();
let width = g.getWidth(); let width = g.getWidth();
let height = g.getHeight(); let height = g.getHeight();
@ -415,6 +393,28 @@ class Status {
this.old_points = []; // record previous points but only when enough distance between them this.old_points = []; // record previous points but only when enough distance between them
this.old_times = []; // the corresponding times this.old_times = []; // the corresponding times
} }
reset_images_cache() {
let tiles_per_diagonals = this.zoomed_in ? 3 : 5;
let screen_width = g.getWidth();
let screen_height = g.getHeight();
this.images_cache = [];
let img_side =
Math.ceil(
Math.sqrt(screen_width * screen_width + screen_height * screen_height) /
tiles_per_diagonals
) + 6; // three extra pixels on each side to allow thick lines
E.defrag();
let limit = tiles_per_diagonals * (tiles_per_diagonals + 1);
for (let i = 0; i < limit; i++) {
let img = Graphics.createArrayBuffer(img_side, img_side, 4, {
msb: true,
});
this.images_cache.push({ image: img, x: -1, y: -1 });
}
}
activate() { activate() {
if (!powersaving) { if (!powersaving) {
return; return;
@ -472,11 +472,14 @@ class Status {
let oldest_point = this.old_points[0]; let oldest_point = this.old_points[0];
let distance_to_oldest = oldest_point.distance(position); let distance_to_oldest = oldest_point.distance(position);
let time_to_oldest = now - this.old_times[0];
// every 3 points we count the distance // every 3 points we count the distance
if (this.gps_coordinates_counter % 3 == 0) { if (this.gps_coordinates_counter % 3 == 0) {
if (distance_to_oldest < 150.0) { if (time_to_oldest > 6 || distance_to_oldest < 150.0) {
// to avoid gps glitches // to avoid gps glitches (sometimes the gps signal will make you jump around)
// however if gps disconnects (time_to_oldest becomes large) we still count the distance
// when it re-activates
this.advanced_distance += distance_to_oldest; this.advanced_distance += distance_to_oldest;
} }
} }
@ -711,36 +714,28 @@ class Status {
} }
tile_image(absolute_tile_x, absolute_tile_y) { tile_image(absolute_tile_x, absolute_tile_y) {
let cached_img = this.images_cache.find((i) => { // in the cache old images are front and recently used ones are back
let cached_img_index = this.images_cache.findIndex((i) => {
return i.x == absolute_tile_x && i.y == absolute_tile_y; return i.x == absolute_tile_x && i.y == absolute_tile_y;
}); });
if (cached_img === undefined) { if (cached_img_index == -1) {
let img = this.compute_tile_image(absolute_tile_x, absolute_tile_y); // console.log("loading", absolute_tile_x, absolute_tile_y);
let limit = this.zoomed_in ? 12 : 30; let old_image = this.images_cache.shift();
if (this.images_cache.length > limit) { this.compute_tile_image(old_image.image, absolute_tile_x, absolute_tile_y);
this.images_cache.shift();
}
this.images_cache.push({ this.images_cache.push({
image: img, image: old_image.image,
x: absolute_tile_x, x: absolute_tile_x,
y: absolute_tile_y, y: absolute_tile_y,
}); });
return img; return old_image.image;
} else { } else {
let cached_img = this.images_cache.splice(cached_img_index, 1)[0];
this.images_cache.push(cached_img);
return cached_img.image; return cached_img.image;
} }
} }
compute_tile_image(absolute_tile_x, absolute_tile_y) { compute_tile_image(img, absolute_tile_x, absolute_tile_y) {
let screen_width = g.getWidth();
let screen_height = g.getHeight();
let tiles_per_diagonals = this.zoomed_in ? 3 : 5;
let img_side = Math.ceil(
Math.sqrt(screen_width * screen_width + screen_height * screen_height) /
tiles_per_diagonals
) + 6; // three extra pixels on each side to allow thick lines
let img = Graphics.createArrayBuffer(img_side, img_side, 4, { msb: true });
img.transparent = img.toColor(1, 1, 1); img.transparent = img.toColor(1, 1, 1);
img.setBgColor(1, 1, 1).clear(); img.setBgColor(1, 1, 1).clear();
@ -748,17 +743,11 @@ class Status {
m.add_to_tile_image(img, absolute_tile_x, absolute_tile_y); m.add_to_tile_image(img, absolute_tile_x, absolute_tile_y);
}); });
this.interests.add_to_tile_image(img, absolute_tile_x, absolute_tile_y); this.interests.add_to_tile_image(img, absolute_tile_x, absolute_tile_y);
return img;
} }
display() {
if (displaying || in_menu) {
return; // don't draw on drawings
}
g.reset();
displaying = true;
g.clear();
if (this.screen == MAP) {
display_map() {
// start_profiling();
let displayed_x = this.displayed_position.lon; let displayed_x = this.displayed_position.lon;
let displayed_y = this.displayed_position.lat; let displayed_y = this.displayed_position.lat;
let tile_x_coord = displayed_x / this.maps[0].side; let tile_x_coord = displayed_x / this.maps[0].side;
@ -780,8 +769,10 @@ class Status {
for (let y = -d; y <= d; y++) { for (let y = -d; y <= d; y++) {
let img = this.tile_image(absolute_tile_x + x, absolute_tile_y + y); let img = this.tile_image(absolute_tile_x + x, absolute_tile_y + y);
let screen_x = (absolute_tile_x + x + 0.5 - tile_x_coord) * diagonal + 3; let screen_x =
let screen_y = -(absolute_tile_y + y + 0.5 - tile_y_coord) * diagonal - 3; (absolute_tile_x + x + 0.5 - tile_x_coord) * diagonal + 3;
let screen_y =
-(absolute_tile_y + y + 0.5 - tile_y_coord) * diagonal - 3;
let rotated_x = screen_x * cos_direction - screen_y * sin_direction; let rotated_x = screen_x * cos_direction - screen_y * sin_direction;
let rotated_y = screen_x * sin_direction + screen_y * cos_direction; let rotated_y = screen_x * sin_direction + screen_y * cos_direction;
@ -791,13 +782,27 @@ class Status {
g.drawImage(img, final_x, final_y, { rotate: angle }); g.drawImage(img, final_x, final_y, { rotate: angle });
} }
} }
// end_profiling("map display");
}
display() {
if (displaying || in_menu) {
return; // don't draw on drawings
}
g.reset();
displaying = true;
g.clear();
if (this.screen == MAP) {
this.display_map();
if (this.position !== null) { if (this.position !== null) {
// start_profiling();
this.display_path(); this.display_path();
// end_profiling("path display");
} }
// start_profiling();
this.display_direction(); this.display_direction();
this.display_stats(); this.display_stats();
// end_profiling("direction and stats display");
} else { } else {
let current_position = 0; let current_position = 0;
if (this.current_segment !== null) { if (this.current_segment !== null) {
@ -1189,8 +1194,6 @@ function load_gps(filename) {
class Path { class Path {
constructor(buffer, offset) { constructor(buffer, offset) {
// let p = Uint16Array(buffer, offset, 1);
// console.log(p);
let points_number = Uint16Array(buffer, offset, 1)[0]; let points_number = Uint16Array(buffer, offset, 1)[0];
offset += 2; offset += 2;
@ -1408,7 +1411,7 @@ function start_gipy(path, maps, interests, heights) {
value: status.zoomed_in, value: status.zoomed_in,
format: (v) => (v ? "In" : "Out"), format: (v) => (v ? "In" : "Out"),
onchange: (v) => { onchange: (v) => {
status.images_cache = []; status.reset_images_cache();
status.zoomed_in = v; status.zoomed_in = v;
}, },
}, },
@ -1486,51 +1489,52 @@ function start_gipy(path, maps, interests, heights) {
}); });
if (simulated) { if (simulated) {
status.starting_time = getTime(); // status.starting_time = getTime();
// let's keep the screen on in simulations // // let's keep the screen on in simulations
Bangle.setLCDTimeout(0); // Bangle.setLCDTimeout(0);
Bangle.setLCDPower(1); // Bangle.setLCDPower(1);
Bangle.loadWidgets(); // i don't know why i cannot load them at start : they would display on splash screen // Bangle.loadWidgets(); // i don't know why i cannot load them at start : they would display on splash screen
function simulate_gps(status) { // function simulate_gps(status) {
if (status.path === null) { // if (status.path === null) {
let map = status.maps[0]; // let map = status.maps[0];
let p1 = new Point(map.start_coordinates[0], map.start_coordinates[1]); // let p1 = new Point(map.start_coordinates[0], map.start_coordinates[1]);
let p2 = new Point( // let p2 = new Point(
map.start_coordinates[0] + map.side * map.grid_size[0], // map.start_coordinates[0] + map.side * map.grid_size[0],
map.start_coordinates[1] + map.side * map.grid_size[1] // map.start_coordinates[1] + map.side * map.grid_size[1]
); // );
let pos = p1.times(1 - fake_gps_point).plus(p2.times(fake_gps_point)); // let pos = p1.times(1 - fake_gps_point).plus(p2.times(fake_gps_point));
if (fake_gps_point < 1) { // if (fake_gps_point < 1) {
fake_gps_point += 0.05; // fake_gps_point += 0.05;
} // }
status.update_position(pos); // status.update_position(pos);
} else { // } else {
if (fake_gps_point > status.path.len - 1 || fake_gps_point < 0) { // if (fake_gps_point > status.path.len - 1 || fake_gps_point < 0) {
return; // return;
} // }
let point_index = Math.floor(fake_gps_point); // let point_index = Math.floor(fake_gps_point);
if (point_index >= status.path.len / 2 - 1) { // if (point_index >= status.path.len / 2 - 1) {
return; // return;
} // }
let p1 = status.path.point(2 * point_index); // use these to approximately follow path // let p1 = status.path.point(2 * point_index); // use these to approximately follow path
let p2 = status.path.point(2 * (point_index + 1)); // let p2 = status.path.point(2 * (point_index + 1));
//let p1 = status.path.point(point_index); // use these to strictly follow path // //let p1 = status.path.point(point_index); // use these to strictly follow path
//let p2 = status.path.point(point_index + 1); // //let p2 = status.path.point(point_index + 1);
let alpha = fake_gps_point - point_index; // let alpha = fake_gps_point - point_index;
let pos = p1.times(1 - alpha).plus(p2.times(alpha)); // let pos = p1.times(1 - alpha).plus(p2.times(alpha));
if (go_backwards) { // if (go_backwards) {
fake_gps_point -= 0.2; // advance simulation // fake_gps_point -= 0.2; // advance simulation
} else { // } else {
fake_gps_point += 0.2; // advance simulation // fake_gps_point += 0.2; // advance simulation
} // }
status.update_position(pos); // console.log(fake_gps_point);
} // status.update_position(pos);
} // }
// }
setInterval(simulate_gps, 500, status); // setInterval(simulate_gps, 500, status);
} else { } else {
status.activate(); status.activate();