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
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
* Waypoints autodetection using the map
* New option: sleep between waypoints

View File

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

View File

@ -7,11 +7,11 @@ let status;
let initial_options = Bangle.getOptions();
let interests_colors = [
[1,1,1], // Waypoints, white
[1,0,0], // Bakery, red
[0,0,1], // DrinkingWater, blue
[0,1,1], // Toilets, cyan
[0,1,0], // Artwork, green
[1, 1, 1], // Waypoints, white
[1, 0, 0], // Bakery, red
[0, 0, 1], // DrinkingWater, blue
[0, 1, 1], // Toilets, cyan
[0, 1, 0], // Artwork, green
];
let Y_OFFSET = 20;
@ -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 {
constructor(buffer, offset, filename) {
this.points_cache = []; // don't refetch points all the time
// header
let color_array = Uint8Array(buffer, offset, 3);
this.color = [
@ -338,7 +317,6 @@ class Interests {
this.binary_interests[i] = binary_interests[i];
}
offset += end;
this.points_cache = [];
return [this, offset];
}
@ -388,7 +366,7 @@ class Status {
this.reaching = null; // which waypoint are we reaching ?
this.distance_to_next_point = null; // how far are we from next point ?
this.projected_point = null;
this.images_cache = [];
this.reset_images_cache();
let width = g.getWidth();
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_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() {
if (!powersaving) {
return;
@ -472,11 +472,14 @@ class Status {
let oldest_point = this.old_points[0];
let distance_to_oldest = oldest_point.distance(position);
let time_to_oldest = now - this.old_times[0];
// every 3 points we count the distance
if (this.gps_coordinates_counter % 3 == 0) {
if (distance_to_oldest < 150.0) {
// to avoid gps glitches
if (time_to_oldest > 6 || distance_to_oldest < 150.0) {
// 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;
}
}
@ -711,54 +714,40 @@ class Status {
}
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;
});
if (cached_img === undefined) {
let img = this.compute_tile_image(absolute_tile_x, absolute_tile_y);
let limit = this.zoomed_in ? 12 : 30;
if (this.images_cache.length > limit) {
this.images_cache.shift();
}
if (cached_img_index == -1) {
// console.log("loading", absolute_tile_x, absolute_tile_y);
let old_image = this.images_cache.shift();
this.compute_tile_image(old_image.image, absolute_tile_x, absolute_tile_y);
this.images_cache.push({
image: img,
image: old_image.image,
x: absolute_tile_x,
y: absolute_tile_y,
});
return img;
return old_image.image;
} else {
let cached_img = this.images_cache.splice(cached_img_index, 1)[0];
this.images_cache.push(cached_img);
return cached_img.image;
}
}
compute_tile_image(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.setBgColor(1,1,1).clear();
compute_tile_image(img, absolute_tile_x, absolute_tile_y) {
img.transparent = img.toColor(1, 1, 1);
img.setBgColor(1, 1, 1).clear();
this.maps.forEach((m) => {
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);
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_y = this.displayed_position.lat;
let tile_x_coord = displayed_x / this.maps[0].side;
@ -780,8 +769,10 @@ class Status {
for (let y = -d; y <= d; 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_y = -(absolute_tile_y + y + 0.5 - tile_y_coord) * diagonal - 3;
let screen_x =
(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_y = screen_x * sin_direction + screen_y * cos_direction;
@ -791,13 +782,27 @@ class Status {
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) {
// start_profiling();
this.display_path();
// end_profiling("path display");
}
// start_profiling();
this.display_direction();
this.display_stats();
// end_profiling("direction and stats display");
} else {
let current_position = 0;
if (this.current_segment !== null) {
@ -1189,8 +1194,6 @@ function load_gps(filename) {
class Path {
constructor(buffer, offset) {
// let p = Uint16Array(buffer, offset, 1);
// console.log(p);
let points_number = Uint16Array(buffer, offset, 1)[0];
offset += 2;
@ -1408,7 +1411,7 @@ function start_gipy(path, maps, interests, heights) {
value: status.zoomed_in,
format: (v) => (v ? "In" : "Out"),
onchange: (v) => {
status.images_cache = [];
status.reset_images_cache();
status.zoomed_in = v;
},
},
@ -1486,51 +1489,52 @@ function start_gipy(path, maps, interests, heights) {
});
if (simulated) {
status.starting_time = getTime();
// let's keep the screen on in simulations
Bangle.setLCDTimeout(0);
Bangle.setLCDPower(1);
Bangle.loadWidgets(); // i don't know why i cannot load them at start : they would display on splash screen
// status.starting_time = getTime();
// // let's keep the screen on in simulations
// Bangle.setLCDTimeout(0);
// Bangle.setLCDPower(1);
// Bangle.loadWidgets(); // i don't know why i cannot load them at start : they would display on splash screen
function simulate_gps(status) {
if (status.path === null) {
let map = status.maps[0];
let p1 = new Point(map.start_coordinates[0], map.start_coordinates[1]);
let p2 = new Point(
map.start_coordinates[0] + map.side * map.grid_size[0],
map.start_coordinates[1] + map.side * map.grid_size[1]
);
let pos = p1.times(1 - fake_gps_point).plus(p2.times(fake_gps_point));
if (fake_gps_point < 1) {
fake_gps_point += 0.05;
}
status.update_position(pos);
} else {
if (fake_gps_point > status.path.len - 1 || fake_gps_point < 0) {
return;
}
let point_index = Math.floor(fake_gps_point);
if (point_index >= status.path.len / 2 - 1) {
return;
}
let p1 = status.path.point(2 * point_index); // use these to approximately follow path
let p2 = status.path.point(2 * (point_index + 1));
//let p1 = status.path.point(point_index); // use these to strictly follow path
//let p2 = status.path.point(point_index + 1);
// function simulate_gps(status) {
// if (status.path === null) {
// let map = status.maps[0];
// let p1 = new Point(map.start_coordinates[0], map.start_coordinates[1]);
// let p2 = new Point(
// map.start_coordinates[0] + map.side * map.grid_size[0],
// map.start_coordinates[1] + map.side * map.grid_size[1]
// );
// let pos = p1.times(1 - fake_gps_point).plus(p2.times(fake_gps_point));
// if (fake_gps_point < 1) {
// fake_gps_point += 0.05;
// }
// status.update_position(pos);
// } else {
// if (fake_gps_point > status.path.len - 1 || fake_gps_point < 0) {
// return;
// }
// let point_index = Math.floor(fake_gps_point);
// if (point_index >= status.path.len / 2 - 1) {
// return;
// }
// let p1 = status.path.point(2 * point_index); // use these to approximately follow path
// let p2 = status.path.point(2 * (point_index + 1));
// //let p1 = status.path.point(point_index); // use these to strictly follow path
// //let p2 = status.path.point(point_index + 1);
let alpha = fake_gps_point - point_index;
let pos = p1.times(1 - alpha).plus(p2.times(alpha));
// let alpha = fake_gps_point - point_index;
// let pos = p1.times(1 - alpha).plus(p2.times(alpha));
if (go_backwards) {
fake_gps_point -= 0.2; // advance simulation
} else {
fake_gps_point += 0.2; // advance simulation
}
status.update_position(pos);
}
}
// if (go_backwards) {
// fake_gps_point -= 0.2; // advance simulation
// } else {
// fake_gps_point += 0.2; // advance simulation
// }
// console.log(fake_gps_point);
// status.update_position(pos);
// }
// }
setInterval(simulate_gps, 500, status);
// setInterval(simulate_gps, 500, status);
} else {
status.activate();