Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions include/ui/radar_projection.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

namespace ui::radar {

constexpr float kKmPerDeg = 111.0f;
constexpr float kDegToRad = 3.14159265f / 180.0f;

/** Offset of lat/lon from the radar center, in km. */
void offsetKmFromCenter(float lat, float lon, float* dx_km, float* dy_km,
float* dist_km);

/** Flat lat/lon as x/y: 1 deg ~ 111 km, north = screen up. */
void latLonToScreen(float lat, float lon, int* out_x, int* out_y);

int distSqFromCenter(int x, int y);

/** Pull (x1,y1) back along the segment from (x0,y0) until inside the ring. */
void clipPointToOuterRing(int x0, int y0, int* x1, int* y1);

} // namespace ui::radar
69 changes: 6 additions & 63 deletions src/ui/radar_display.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "hardware/display_font.h"
#include "services/adsb_client.h"
#include "services/radar_location.h"
#include "ui/radar_projection.h"
#include "ui/radar_range.h"
#include "ui/radar_theme.h"
#include "ui/runway_overlay.h"
Expand All @@ -33,6 +34,11 @@ uint16_t kColorRunwayLabel = 0x7DFF;

namespace {

using radar::clipPointToOuterRing;
using radar::distSqFromCenter;
using radar::latLonToScreen;
using radar::offsetKmFromCenter;

bool s_label_metrics_ready = false;
bool s_cardinal_use_vlw = false;
bool s_scale_use_vlw = false;
Expand Down Expand Up @@ -197,51 +203,15 @@ void initPalette() {
radar::kRunwayLabelB);
}

constexpr float kKmPerDeg = 111.0f;
constexpr float kDegToRad = 3.14159265f / 180.0f;

void offsetKmFromCenter(float lat, float lon, float* dx_km, float* dy_km,
float* dist_km) {
// Longitude degrees shrink toward the poles; scale by cos(latitude) so
// east-west distance isn't overstated away from the equator.
const float center_lat_rad =
static_cast<float>(services::location::lat()) * kDegToRad;
*dx_km = static_cast<float>(lon - services::location::lon()) * kKmPerDeg *
cosf(center_lat_rad);
*dy_km =
static_cast<float>(lat - services::location::lat()) * kKmPerDeg;
*dist_km = sqrtf((*dx_km) * (*dx_km) + (*dy_km) * (*dy_km));
}

float innerRingMaxKm() {
const float outer_km = radar::rangeCurrent().outer_km;
return outer_km * (static_cast<float>(radar::kGridOuterRadius -
radar::kAircraftInsideRingInsetPx) /
static_cast<float>(radar::kGridOuterRadius));
}

/** Flat lat/lon as x/y: 1° ≈ 111 km, north = screen up. */
void latLonToScreen(float lat, float lon, int* out_x, int* out_y) {
const float outer_km = radar::rangeCurrent().outer_km;
const float px_per_km = static_cast<float>(radar::kGridOuterRadius) / outer_km;

float dx_km = 0.0f;
float dy_km = 0.0f;
float dist_km = 0.0f;
offsetKmFromCenter(lat, lon, &dx_km, &dy_km, &dist_km);

*out_x = radar::kCenterX + static_cast<int>(lroundf(dx_km * px_per_km));
*out_y = radar::kCenterY - static_cast<int>(lroundf(dy_km * px_per_km));
}

bool isInsideOuterRingKm(float dist_km) { return dist_km <= innerRingMaxKm(); }

int distSqFromCenter(int x, int y) {
const int dx = x - radar::kCenterX;
const int dy = y - radar::kCenterY;
return dx * dx + dy * dy;
}

bool isInsideOuterRing(int x, int y) {
const int max_r = radar::kGridOuterRadius - radar::kAircraftInsideRingInsetPx;
return distSqFromCenter(x, y) <= max_r * max_r;
Expand Down Expand Up @@ -275,33 +245,6 @@ void drawBeyondRingDot(int x, int y) {
radar::kColorAircraft);
}

void clipPointToOuterRing(int x0, int y0, int* x1, int* y1) {
const int max_r = radar::kGridOuterRadius;
const int max_r_sq = max_r * max_r;
if (distSqFromCenter(*x1, *y1) <= max_r_sq) {
return;
}

const int dx = *x1 - x0;
const int dy = *y1 - y0;
float t = 1.0f;
for (int step = 0; step < 20; ++step) {
const int px = x0 + static_cast<int>(lroundf(dx * t));
const int py = y0 + static_cast<int>(lroundf(dy * t));
if (distSqFromCenter(px, py) <= max_r_sq) {
*x1 = px;
*y1 = py;
return;
}
t -= 0.05f;
if (t <= 0.0f) {
*x1 = x0;
*y1 = y0;
return;
}
}
}

int speedLineLengthPx(float gs_knots) {
if (gs_knots <= 0.0f) {
return 0;
Expand Down
69 changes: 69 additions & 0 deletions src/ui/radar_projection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#include "ui/radar_projection.h"

#include <cmath>

#include "services/radar_location.h"
#include "ui/radar_range.h"
#include "ui/radar_theme.h"

namespace ui::radar {

void offsetKmFromCenter(float lat, float lon, float* dx_km, float* dy_km,
float* dist_km) {
// Longitude degrees shrink toward the poles; scale by cos(latitude) so
// east-west distance isn't overstated away from the equator.
const float center_lat_rad =
static_cast<float>(services::location::lat()) * kDegToRad;
*dx_km = static_cast<float>(lon - services::location::lon()) * kKmPerDeg *
cosf(center_lat_rad);
*dy_km = static_cast<float>(lat - services::location::lat()) * kKmPerDeg;
*dist_km = sqrtf((*dx_km) * (*dx_km) + (*dy_km) * (*dy_km));
}

void latLonToScreen(float lat, float lon, int* out_x, int* out_y) {
const float outer_km = rangeCurrent().outer_km;
const float px_per_km = static_cast<float>(kGridOuterRadius) / outer_km;

float dx_km = 0.0f;
float dy_km = 0.0f;
float dist_km = 0.0f;
offsetKmFromCenter(lat, lon, &dx_km, &dy_km, &dist_km);

*out_x = kCenterX + static_cast<int>(lroundf(dx_km * px_per_km));
*out_y = kCenterY - static_cast<int>(lroundf(dy_km * px_per_km));
}

int distSqFromCenter(int x, int y) {
const int dx = x - kCenterX;
const int dy = y - kCenterY;
return dx * dx + dy * dy;
}

void clipPointToOuterRing(int x0, int y0, int* x1, int* y1) {
const int max_r = kGridOuterRadius;
const int max_r_sq = max_r * max_r;
if (distSqFromCenter(*x1, *y1) <= max_r_sq) {
return;
}

const int dx = *x1 - x0;
const int dy = *y1 - y0;
float t = 1.0f;
for (int step = 0; step < 20; ++step) {
const int px = x0 + static_cast<int>(lroundf(dx * t));
const int py = y0 + static_cast<int>(lroundf(dy * t));
if (distSqFromCenter(px, py) <= max_r_sq) {
*x1 = px;
*y1 = py;
return;
}
t -= 0.05f;
if (t <= 0.0f) {
*x1 = x0;
*y1 = y0;
return;
}
}
}

} // namespace ui::radar
68 changes: 6 additions & 62 deletions src/ui/runway_overlay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,18 @@
#include "data/large_airports.h"
#include "hardware/display_font.h"
#include "services/radar_location.h"
#include "ui/radar_projection.h"
#include "ui/radar_range.h"
#include "ui/radar_theme.h"

namespace ui::runway {
namespace {

constexpr float kKmPerDeg = 111.0f;
constexpr float kDegToRad = 3.14159265f / 180.0f;
using radar::clipPointToOuterRing;
using radar::distSqFromCenter;
using radar::latLonToScreen;
using radar::offsetKmFromCenter;

constexpr size_t kMaxAirportLabels = 32;

bool s_in_range[data::large_airports::kAirportCount];
Expand Down Expand Up @@ -71,66 +75,6 @@ void applyRunwayLabelStyle(lgfx::LGFXBase& gfx) {

float e7ToDeg(int32_t e7) { return static_cast<float>(e7) * 1e-7f; }

void offsetKmFromCenter(float lat, float lon, float* dx_km, float* dy_km,
float* dist_km) {
// Longitude degrees shrink toward the poles; scale by cos(latitude) so
// east-west distance isn't overstated away from the equator.
const float center_lat_rad =
static_cast<float>(services::location::lat()) * kDegToRad;
*dx_km = static_cast<float>(lon - services::location::lon()) * kKmPerDeg *
cosf(center_lat_rad);
*dy_km =
static_cast<float>(lat - services::location::lat()) * kKmPerDeg;
*dist_km = sqrtf((*dx_km) * (*dx_km) + (*dy_km) * (*dy_km));
}

void latLonToScreen(float lat, float lon, int* out_x, int* out_y) {
const float outer_km = radar::rangeCurrent().outer_km;
const float px_per_km =
static_cast<float>(radar::kGridOuterRadius) / outer_km;

float dx_km = 0.0f;
float dy_km = 0.0f;
float dist_km = 0.0f;
offsetKmFromCenter(lat, lon, &dx_km, &dy_km, &dist_km);

*out_x = radar::kCenterX + static_cast<int>(lroundf(dx_km * px_per_km));
*out_y = radar::kCenterY - static_cast<int>(lroundf(dy_km * px_per_km));
}

int distSqFromCenter(int x, int y) {
const int dx = x - radar::kCenterX;
const int dy = y - radar::kCenterY;
return dx * dx + dy * dy;
}

void clipPointToOuterRing(int x0, int y0, int* x1, int* y1) {
const int max_r = radar::kGridOuterRadius;
const int max_r_sq = max_r * max_r;
if (distSqFromCenter(*x1, *y1) <= max_r_sq) {
return;
}

const int dx = *x1 - x0;
const int dy = *y1 - y0;
float t = 1.0f;
for (int step = 0; step < 20; ++step) {
const int px = x0 + static_cast<int>(lroundf(dx * t));
const int py = y0 + static_cast<int>(lroundf(dy * t));
if (distSqFromCenter(px, py) <= max_r_sq) {
*x1 = px;
*y1 = py;
return;
}
t -= 0.05f;
if (t <= 0.0f) {
*x1 = x0;
*y1 = y0;
return;
}
}
}

bool segmentIntersectsDisc(int x0, int y0, int x1, int y1) {
const int cx = radar::kCenterX;
const int cy = radar::kCenterY;
Expand Down