mirror of
https://github.com/eried/portapack-mayhem.git
synced 2025-05-06 08:45:01 -04:00
GeoMap and Jammer clean up
Jammer ranges can now be set with center and width GeoMap can be moved with touch GeoMap negative coordinates bugfix Replay app throws error if no files found instead of crashing
This commit is contained in:
parent
1a6d80cd10
commit
cb880258fb
7 changed files with 499 additions and 304 deletions
|
@ -22,7 +22,6 @@
|
|||
|
||||
#include "ui_geomap.hpp"
|
||||
|
||||
#include "adsb.hpp"
|
||||
#include "portapack.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
@ -53,18 +52,23 @@ GeoPos::GeoPos(
|
|||
set_lat(0);
|
||||
set_lon(0);
|
||||
|
||||
const auto changed = [this](int32_t) {
|
||||
if (on_change)
|
||||
on_change();
|
||||
const auto changed_fn = [this](int32_t) {
|
||||
if (on_change && report_change)
|
||||
on_change(altitude(), lat(), lon());
|
||||
};
|
||||
|
||||
field_altitude.on_change = changed;
|
||||
field_lat_degrees.on_change = changed;
|
||||
field_lat_minutes.on_change = changed;
|
||||
field_lat_seconds.on_change = changed;
|
||||
field_lon_degrees.on_change = changed;
|
||||
field_lon_minutes.on_change = changed;
|
||||
field_lon_seconds.on_change = changed;
|
||||
field_altitude.on_change = changed_fn;
|
||||
field_lat_degrees.on_change = changed_fn;
|
||||
field_lat_minutes.on_change = changed_fn;
|
||||
field_lat_seconds.on_change = changed_fn;
|
||||
field_lon_degrees.on_change = changed_fn;
|
||||
field_lon_minutes.on_change = changed_fn;
|
||||
field_lon_seconds.on_change = changed_fn;
|
||||
}
|
||||
|
||||
// Stupid hack to avoid an event loop
|
||||
void GeoPos::set_report_change(bool v) {
|
||||
report_change = v;
|
||||
}
|
||||
|
||||
void GeoPos::focus() {
|
||||
|
@ -77,14 +81,14 @@ void GeoPos::set_altitude(int32_t altitude) {
|
|||
|
||||
void GeoPos::set_lat(float lat) {
|
||||
field_lat_degrees.set_value(lat);
|
||||
field_lat_minutes.set_value((uint32_t)(lat / (1.0 / 60)) % 60);
|
||||
field_lat_seconds.set_value((uint32_t)(lat / (1.0 / 3600)) % 60);
|
||||
field_lat_minutes.set_value((uint32_t)abs(lat / (1.0 / 60)) % 60);
|
||||
field_lat_seconds.set_value((uint32_t)abs(lat / (1.0 / 3600)) % 60);
|
||||
}
|
||||
|
||||
void GeoPos::set_lon(float lon) {
|
||||
field_lon_degrees.set_value(lon);
|
||||
field_lon_minutes.set_value((uint32_t)(lon / (1.0 / 60)) % 60);
|
||||
field_lon_seconds.set_value((uint32_t)(lon / (1.0 / 3600)) % 60);
|
||||
field_lon_minutes.set_value((uint32_t)abs(lon / (1.0 / 60)) % 60);
|
||||
field_lon_seconds.set_value((uint32_t)abs(lon / (1.0 / 3600)) % 60);
|
||||
}
|
||||
|
||||
float GeoPos::lat() {
|
||||
|
@ -103,19 +107,102 @@ void GeoPos::set_read_only(bool v) {
|
|||
set_focusable(~v);
|
||||
};
|
||||
|
||||
void GeoMapView::focus() {
|
||||
if (!file_error) {
|
||||
geopos.focus();
|
||||
move_map();
|
||||
} else
|
||||
nav_.display_modal("No map", "No world_map.bin file in\n/ADSB/ directory", ABORT, nullptr);
|
||||
GeoMap::GeoMap(
|
||||
Rect parent_rect
|
||||
) : Widget { parent_rect }
|
||||
{
|
||||
//set_focusable(true);
|
||||
}
|
||||
|
||||
GeoMapView::~GeoMapView() {
|
||||
void GeoMap::paint(Painter& painter) {
|
||||
Coord line;
|
||||
std::array<ui::Color, 240> map_line_buffer;
|
||||
//Color border;
|
||||
const auto r = screen_rect();
|
||||
|
||||
// Ony redraw map if it moved by at least 1 pixel
|
||||
if ((x_pos != prev_x_pos) || (y_pos != prev_y_pos)) {
|
||||
for (line = 0; line < r.height(); line++) {
|
||||
map_file.seek(4 + ((x_pos + (map_width * (y_pos + line))) << 1));
|
||||
map_file.read(map_line_buffer.data(), r.width() << 1);
|
||||
display.draw_pixels({ 0, r.top() + line, r.width(), 1 }, map_line_buffer);
|
||||
}
|
||||
|
||||
prev_x_pos = x_pos;
|
||||
prev_y_pos = y_pos;
|
||||
}
|
||||
|
||||
if (mode_ == PROMPT) {
|
||||
// Cross
|
||||
display.fill_rectangle({ r.center() - Point(16, 1), { 32, 2 } }, Color::red());
|
||||
display.fill_rectangle({ r.center() - Point(1, 16), { 2, 32 } }, Color::red());
|
||||
} else {
|
||||
draw_bearing({ 120, 32 + 144 }, angle_, 16, Color::red());
|
||||
}
|
||||
|
||||
/*if (has_focus() || highlighted())
|
||||
border = style().foreground;
|
||||
else
|
||||
border = Color::grey();
|
||||
|
||||
painter.draw_rectangle(
|
||||
{ r.location().x(), r.location().y(), r.size().width(), r.size().height() },
|
||||
border
|
||||
);*/
|
||||
}
|
||||
|
||||
void GeoMapView::draw_bearing(const Point origin, const uint32_t angle, uint32_t size, const Color color) {
|
||||
bool GeoMap::on_touch(const TouchEvent event) {
|
||||
if (event.type == TouchEvent::Type::Start) {
|
||||
set_highlighted(true);
|
||||
if (on_move) {
|
||||
Point p = event.point - screen_rect().center();
|
||||
on_move(p.x() / 2.0 * lon_ratio, p.y() / 2.0 * lat_ratio);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GeoMap::move(const float lon, const float lat) {
|
||||
lon_ = lon;
|
||||
lat_ = lat;
|
||||
|
||||
Rect map_rect = screen_rect();
|
||||
|
||||
// Map is in Equidistant "Plate Carrée" projection
|
||||
x_pos = map_center_x - (map_rect.width() / 2) + (lon_ / lon_ratio);
|
||||
y_pos = map_center_y - (map_rect.height() / 2) + (lat_ / lat_ratio);
|
||||
|
||||
// Cap position
|
||||
if (x_pos > (map_width - map_rect.width()))
|
||||
x_pos = map_width - map_rect.width();
|
||||
if (y_pos > (map_height + map_rect.height()))
|
||||
y_pos = map_height - map_rect.height();
|
||||
}
|
||||
|
||||
bool GeoMap::init() {
|
||||
auto result = map_file.open("ADSB/world_map.bin");
|
||||
if (result.is_valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
map_file.read(&map_width, 2);
|
||||
map_file.read(&map_height, 2);
|
||||
|
||||
map_center_x = map_width >> 1;
|
||||
map_center_y = map_height >> 1;
|
||||
|
||||
lon_ratio = 180.0 / map_center_x;
|
||||
lat_ratio = 90.0 / map_center_y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GeoMap::set_mode(GeoMapMode mode) {
|
||||
mode_ = mode;
|
||||
}
|
||||
|
||||
void GeoMap::draw_bearing(const Point origin, const uint32_t angle, uint32_t size, const Color color) {
|
||||
Point arrow_a, arrow_b, arrow_c;
|
||||
|
||||
for (size_t thickness = 0; thickness < 3; thickness++) {
|
||||
|
@ -131,62 +218,43 @@ void GeoMapView::draw_bearing(const Point origin, const uint32_t angle, uint32_t
|
|||
}
|
||||
}
|
||||
|
||||
void GeoMapView::move_map() {
|
||||
Coord line;
|
||||
int32_t x_pos, y_pos;
|
||||
std::array<ui::Color, 240> map_line_buffer;
|
||||
|
||||
auto r = screen_rect();
|
||||
Rect map_rect = { r.left(), r.top() + banner_height, r.width(), r.height() - banner_height };
|
||||
|
||||
altitude_ = geopos.altitude();
|
||||
lat_ = geopos.lat();
|
||||
lon_ = geopos.lon();
|
||||
|
||||
// Map is in Equidistant "Plate Carrée" projection
|
||||
x_pos = map_center_x - (map_rect.width() / 2) + ((lat_ * map_center_x) / 180);
|
||||
y_pos = map_center_y - (map_rect.height() / 2) + ((lon_ * map_center_y) / 90);
|
||||
|
||||
if (x_pos > (map_width - map_rect.width()))
|
||||
x_pos = map_width - map_rect.width();
|
||||
if (y_pos > (map_height + map_rect.height()))
|
||||
y_pos = map_height - map_rect.height();
|
||||
|
||||
for (line = 0; line < map_rect.height(); line++) {
|
||||
map_file.seek(4 + ((x_pos + (map_width * (y_pos + line))) << 1));
|
||||
map_file.read(map_line_buffer.data(), map_rect.width() << 1);
|
||||
display.draw_pixels({ 0, map_rect.top() + line, map_rect.width(), 1 }, map_line_buffer);
|
||||
}
|
||||
|
||||
if (mode_ == PROMPT) {
|
||||
display.fill_rectangle({ map_rect.center() - Point(16, 1), { 32, 2 } }, Color::red());
|
||||
display.fill_rectangle({ map_rect.center() - Point(1, 16), { 2, 32 } }, Color::red());
|
||||
} else {
|
||||
draw_bearing({ 120, 32 + 144 }, angle_, 16, Color::red());
|
||||
}
|
||||
void GeoMapView::focus() {
|
||||
if (!file_error) {
|
||||
geopos.focus();
|
||||
} else
|
||||
nav_.display_modal("No map", "No world_map.bin file in\n/ADSB/ directory", ABORT, nullptr);
|
||||
}
|
||||
|
||||
void GeoMapView::setup() {
|
||||
auto result = map_file.open("ADSB/world_map.bin");
|
||||
if (result.is_valid()) {
|
||||
file_error = true;
|
||||
return;
|
||||
}
|
||||
|
||||
map_file.read(&map_width, 2);
|
||||
map_file.read(&map_height, 2);
|
||||
|
||||
map_center_x = map_width >> 1;
|
||||
map_center_y = map_height >> 1;
|
||||
|
||||
add_child(&geopos);
|
||||
add_children({
|
||||
&geopos,
|
||||
&geomap
|
||||
});
|
||||
|
||||
geopos.set_altitude(altitude_);
|
||||
geopos.set_lat(lat_);
|
||||
geopos.set_lon(lon_);
|
||||
|
||||
geopos.on_change = [this]() {
|
||||
move_map();
|
||||
geopos.on_change = [this](int32_t altitude, float lat, float lon) {
|
||||
altitude_ = altitude;
|
||||
lat_ = lat;
|
||||
lon_ = lon;
|
||||
geomap.move(lon_, lat_);
|
||||
geomap.set_dirty();
|
||||
};
|
||||
|
||||
geomap.on_move = [this](float move_x, float move_y) {
|
||||
lon_ += move_x;
|
||||
lat_ += move_y;
|
||||
|
||||
// Stupid hack to avoid an event loop
|
||||
geopos.set_report_change(false);
|
||||
geopos.set_lon(lon_);
|
||||
geopos.set_lat(lat_);
|
||||
geopos.set_report_change(true);
|
||||
|
||||
geomap.move(lon_, lat_);
|
||||
geomap.set_dirty();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -206,8 +274,15 @@ GeoMapView::GeoMapView(
|
|||
angle_ (angle)
|
||||
{
|
||||
mode_ = DISPLAY;
|
||||
|
||||
file_error = !geomap.init();
|
||||
if (file_error) return;
|
||||
|
||||
setup();
|
||||
|
||||
geomap.set_mode(mode_);
|
||||
geomap.move(lon_, lat_);
|
||||
|
||||
geopos.set_read_only(true);
|
||||
}
|
||||
|
||||
|
@ -224,10 +299,16 @@ GeoMapView::GeoMapView(
|
|||
lon_ (lon)
|
||||
{
|
||||
mode_ = PROMPT;
|
||||
setup();
|
||||
|
||||
file_error = !geomap.init();
|
||||
if (file_error) return;
|
||||
|
||||
setup();
|
||||
add_child(&button_ok);
|
||||
|
||||
geomap.set_mode(mode_);
|
||||
geomap.move(lon_, lat_);
|
||||
|
||||
button_ok.on_select = [this, on_done, &nav](Button&) {
|
||||
if (on_done)
|
||||
on_done(altitude_, lat_, lon_);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue