bool Segment(Canvas &canvas, int x, int y, unsigned radius, Angle start, Angle end, bool horizon) { // dont draw if out of view if (!IsCircleVisible(canvas, x, y, radius)) return false; const int istart = NATIVE_TO_INT(start.Native()); const int iend = NATIVE_TO_INT(end.Native()); unsigned npoly = 0; RasterPoint pt[67]; // add center point if (!horizon) { pt[0].x = x; pt[0].y = y; npoly = 1; } segment_poly(pt, x, y, radius, istart, iend, npoly); assert(npoly <= ARRAY_SIZE(pt)); if (npoly) canvas.DrawTriangleFan(pt, npoly); return true; }
bool KeyHole(Canvas &canvas, PixelScalar x, PixelScalar y, UPixelScalar radius, Angle start, Angle end, UPixelScalar inner_radius) { // dont draw if out of view PixelRect rc, bounds; SetRect(&rc, 0, 0, canvas.get_width(), canvas.get_height()); SetRect(&bounds, x - radius, y - radius, x + radius, y + radius); if (!IntersectRect(&bounds, &bounds, &rc)) return false; const int istart = NATIVE_TO_INT(start.Native()); const int iend = NATIVE_TO_INT(end.Native()); int npoly = 0; RasterPoint pt[66*2]; segment_poly(pt, x, y, radius, istart, iend, npoly); segment_poly(pt, x, y, inner_radius, iend, istart, npoly); assert(npoly <= 66*2); if (npoly) canvas.DrawPolygon(pt, npoly); return true; }
bool Segment(Canvas &canvas, PixelScalar x, PixelScalar y, UPixelScalar radius, Angle start, Angle end, bool horizon) { // dont draw if out of view PixelRect rc, bounds; SetRect(&rc, 0, 0, canvas.get_width(), canvas.get_height()); SetRect(&bounds, x - radius, y - radius, x + radius, y + radius); if (!IntersectRect(&bounds, &bounds, &rc)) return false; const int istart = NATIVE_TO_INT(start.Native()); const int iend = NATIVE_TO_INT(end.Native()); int npoly = 0; RasterPoint pt[66]; // add center point if (!horizon) { pt[0].x = x; pt[0].y = y; npoly = 1; } segment_poly(pt, x, y, radius, istart, iend, npoly); assert(npoly <= 66); if (npoly) canvas.DrawTriangleFan(pt, npoly); return true; }
gcc_const static GeoPoint clip_latitude(const GeoPoint origin, const GeoPoint pt, Angle at) { Angle dx = pt.longitude - origin.longitude; Angle dy = pt.latitude - origin.latitude; Angle ey = at - origin.latitude; Angle ex = ey * (dx.Native() / dy.Native()); return GeoPoint(origin.longitude + ex, at); }
gcc_const static GeoPoint clip_longitude(const GeoPoint origin, const GeoPoint pt, Angle at) { Angle dx = pt.longitude - origin.longitude; Angle dy = pt.latitude - origin.latitude; Angle ex = at - origin.longitude; Angle ey = ex * (dy.Native() / dx.Native()); return GeoPoint(at, origin.latitude + ey); }
gcc_pure static GeoPoint IntermediatePoint(const GeoPoint &loc1, const GeoPoint &loc2, Angle dthis, Angle dtotal) { assert(loc1.IsValid()); assert(loc2.IsValid()); if (loc1.longitude == loc2.longitude && loc1.latitude == loc2.latitude) return loc1; if (!positive(dtotal.Native())) return loc1; assert(dthis <= dtotal && !negative(dthis.Native())); const fixed A = (dtotal - dthis).sin(); const fixed B = dthis.sin(); const auto sc1 = loc1.latitude.SinCos(); const fixed sin_loc1_lat = sc1.first, cos_loc1_lat = sc1.second; const auto sc2 = loc2.latitude.SinCos(); const fixed sin_loc2_lat = sc2.first, cos_loc2_lat = sc2.second; const auto sc3 = loc1.longitude.SinCos(); const fixed sin_loc1_lon = sc3.first, cos_loc1_lon = sc3.second; const auto sc4 = loc2.longitude.SinCos(); const fixed sin_loc2_lon = sc4.first, cos_loc2_lon = sc4.second; const fixed a_cos_loc1_lat = SmallMult(A, cos_loc1_lat); const fixed b_cos_loc2_lat = SmallMult(B, cos_loc2_lat); const fixed x = SmallMult(a_cos_loc1_lat, cos_loc1_lon) + SmallMult(b_cos_loc2_lat, cos_loc2_lon); const fixed y = SmallMult(a_cos_loc1_lat, sin_loc1_lon) + SmallMult(b_cos_loc2_lat, sin_loc2_lon); const fixed z = SmallMult(A, sin_loc1_lat) + SmallMult(B, sin_loc2_lat); GeoPoint loc3; loc3.latitude = Angle::FromXY(TinyHypot(x, y), z); loc3.longitude = Angle::FromXY(x, y); loc3.Normalize(); // ensure longitude is within -180:180 #ifdef INSTRUMENT_TASK count_distbearing++; #endif return loc3; }
gcc_const static std::pair<unsigned,unsigned> AngleToDonutVertices(Angle start, Angle end) { static constexpr Angle epsilon = Angle::FullCircle() / int(GLDonutVertices::CIRCLE_SIZE * 4u); const Angle delta = end - start; if (fabs(delta.AsDelta().Native()) <= epsilon.Native()) /* full circle */ return std::make_pair(0u, unsigned(GLDonutVertices::MAX_ANGLE)); const unsigned istart = AngleToDonutVertex(start); unsigned iend = AngleToDonutVertex(end); if (istart == iend && delta > epsilon) { if (end - start >= Angle::HalfCircle()) /* nearly full circle, round down the end */ iend = GLDonutVertices::PreviousAngle(iend); else /* slightly larger than epsilon: draw at least two indices */ iend = GLDonutVertices::NextAngle(iend); } return std::make_pair(istart, iend); }
void DigitEntry::SetLongitude(Angle value) { // TODO: support all CoordinateFormats value = value.AsBearing(); assert(length == 9); assert(columns[0].type == Column::Type::EAST_WEST); assert(columns[1].type == Column::Type::DIGIT19); assert(columns[2].type == Column::Type::DIGIT); assert(columns[4].type == Column::Type::DIGIT6); assert(columns[5].type == Column::Type::DIGIT); assert(columns[7].type == Column::Type::DIGIT6); assert(columns[8].type == Column::Type::DIGIT); columns[0].value = negative(value.Native()); const fixed degrees = fabs(value.Degrees()); const unsigned i_degrees = std::min(unsigned(degrees), 180u); const unsigned full_seconds = unsigned(degrees * 3600u) % 3600u; const unsigned minutes = std::min(full_seconds / 60u, 59u); const unsigned seconds = full_seconds % 60u; columns[1].value = i_degrees / 10; columns[2].value = i_degrees % 10; columns[4].value = minutes / 10; columns[5].value = minutes % 10; columns[7].value = seconds / 10; columns[8].value = seconds % 10; Invalidate(); }
gcc_const static unsigned AngleToDonutVertex(Angle angle) { return GLDonutVertices::ImportAngle(NATIVE_TO_INT(angle.Native()) + ARRAY_SIZE(ISINETABLE) * 3u / 4u, ARRAY_SIZE(ISINETABLE)); }
bool Annulus(Canvas &canvas, PixelPoint center, unsigned radius, Angle start, Angle end, unsigned inner_radius) { // dont draw if out of view if (!IsCircleVisible(canvas, center, radius)) return false; const int istart = NATIVE_TO_INT(start.Native()); const int iend = NATIVE_TO_INT(end.Native()); unsigned npoly = 0; BulkPixelPoint pt[66*2]; segment_poly(pt, center, radius, istart, iend, npoly); segment_poly(pt, center, inner_radius, iend, istart, npoly, false); assert(npoly <= ARRAY_SIZE(pt)); if (npoly) canvas.DrawPolygon(pt, npoly); return true; }
bool KeyHole(Canvas &canvas, int x, int y, unsigned radius, Angle start, Angle end, unsigned inner_radius) { // dont draw if out of view if (!IsCircleVisible(canvas, x, y, radius)) return false; const int istart = NATIVE_TO_INT(start.Native()); const int iend = NATIVE_TO_INT(end.Native()); unsigned npoly = 0; RasterPoint pt[66*2]; segment_poly(pt, x, y, radius, istart, iend, npoly); segment_poly(pt, x, y, inner_radius, iend, istart, npoly); assert(npoly < ARRAY_SIZE(pt)); if (npoly) canvas.DrawPolygon(pt, npoly); return true; }
static void FormatLongitude(char *buffer, size_t buffer_size, Angle longitude) { // Calculate Longitude sign char sign = negative(longitude.Native()) ? 'W' : 'E'; double mlong(longitude.AbsoluteDegrees()); int dd = (int)mlong; // Calculate minutes double mins = (mlong - dd) * 60.0; // Save the string to the buffer snprintf(buffer, buffer_size, "%02d%06.3f,%c", dd, mins, sign); }
static int Direction(const GeoPoint &p0, const GeoPoint &p1, const GeoPoint &p2, fixed tolerance) { // // In this program we frequently want to look at three consecutive // points, p0, p1, and p2, and determine whether p2 has taken a turn // to the left or a turn to the right. // // We can do this by by translating the points so that p1 is at the origin, // then taking the cross product of p0 and p2. The result will be positive, // negative, or 0, meaning respectively that p2 has turned right, left, or // is on a straight line. // const Angle a = (p0.longitude - p1.longitude) * (p2.latitude - p1.latitude); const Angle b = (p2.longitude - p1.longitude) * (p0.latitude - p1.latitude); if (negative(tolerance)) /* auto-tolerance - this has been verified by experiment */ tolerance = std::max(fabs(a.Native()), fabs(b.Native())) / 10; return (a - b).Sign(tolerance); }
void DigitEntry::SetLongitude(Angle value, CoordinateFormat format) { // Longitude in floating point degrees value = value.AsDelta(); const fixed degrees = fabs(value.Degrees()); // Check the first three columns here assert(columns[0].type == Column::Type::EAST_WEST); assert(columns[1].type == Column::Type::DIGIT19); assert(columns[2].type == Column::Type::DIGIT); columns[0].value = negative(value.Native()); // Set up and check the remaining digits SetDigits(degrees, format, false); Invalidate(); }
void UpdateInfoBoxCircleDiameter(InfoBoxData &data) { if (!CommonInterface::Basic().airspeed_available.IsValid()) { data.SetInvalid(); return; } const Angle turn_rate = CommonInterface::Calculated().turn_rate_heading_smoothed.Absolute(); // deal with div zero and small turn rates if (turn_rate < Angle::Degrees(1)) { data.SetInvalid(); return; } const fixed circle_diameter = CommonInterface::Basic().true_airspeed / turn_rate.Radians() * fixed(2); // convert turn rate to radians/s and double it to get estimated circle diameter if (circle_diameter > fixed (2000)){ // arbitrary estimated that any diameter bigger than 2km will not be interesting data.SetInvalid(); return; } TCHAR buffer[32]; Unit unit = FormatSmallUserDistance(buffer, circle_diameter, false, 0); data.SetValue (buffer); data.SetValueUnit(unit); const fixed circle_duration = Angle::FullCircle().Native() / turn_rate.Native(); StaticString<16> duration_buffer; duration_buffer.Format(_T("%u s"), int(circle_duration)); _tcscpy (buffer, duration_buffer); data.SetComment (buffer); }
gcc_pure int AngleToWidth(Angle angle) const { return (int)(angle.Native() * x_scale); }
gcc_pure int AngleToHeight(Angle angle) const { return (int)(angle.Native() * y_scale); }
gcc_const static unsigned AngleToDonutVertex(Angle angle) { return (NATIVE_TO_INT(angle.Native()) * 64 / 4096 + 48) & 0x3e; }