gipy: fixed perf issues in new display algorithm
parent
4da1282dec
commit
bd3f4489c4
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
urgent TODO:
|
||||
|
||||
- prefetch tiles ?
|
||||
- update documentation to reflect new display ?
|
||||
- add an image for the arrow ?
|
||||
|
||||
|
|
|
|||
218
apps/gipy/app.js
218
apps/gipy/app.js
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue