27#include <wx/datetime.h>
30#include <wx/translation.h>
37static wxTimeSpan RoundToMinutes(
const wxTimeSpan &span) {
38 auto minutes = span.GetMinutes() % 60;
39 auto seconds = span.GetSeconds() % 60;
40 if (seconds > 30) minutes += 1;
41 return wxTimeSpan(span.GetHours(), minutes, 0);
44wxString toSDMM(
int NEflag,
double a,
bool hi_precision) {
67 }
else if (NEflag == 2) {
77 switch (g_iSDMMFormat) {
80 if (hi_precision) mpy = mpy * 1000;
82 m = (long)wxRound((a - (
double)d) * mpy);
84 if (!NEflag || NEflag < 1 || NEflag > 2)
87 s.Printf(
"%d%c %02ld.%04ld'", d, 0x00B0, m / 10000, m % 10000);
89 s.Printf(
"%d%c %02ld.%01ld'", d, 0x00B0, m / 10, m % 10);
93 s.Printf(
"%02d%c %02ld.%04ld' %c", d, 0x00B0, m / 10000,
96 s.Printf(
"%03d%c %02ld.%04ld' %c", d, 0x00B0, m / 10000,
99 s.Printf(
"%02d%c %02ld.%01ld' %c", d, 0x00B0, m / 10, (m % 10), c);
101 s.Printf(
"%03d%c %02ld.%01ld' %c", d, 0x00B0, m / 10, (m % 10), c);
111 s.Printf(
"%03.4f", ang);
114 m = (long)((a - (
double)d) * 60);
116 if (hi_precision) mpy = mpy * 100;
117 long sec = (long)((a - (
double)d - (((double)m) / 60)) * 3600 * mpy);
119 if (!NEflag || NEflag < 1 || NEflag > 2)
122 s.Printf(
"%d%c %ld'%ld.%ld\"", d, 0x00B0, m, sec / 1000, sec % 1000);
124 s.Printf(
"%d%c %ld'%ld.%ld\"", d, 0x00B0, m, sec / 10, sec % 10);
128 s.Printf(
"%02d%c %02ld' %02ld.%03ld\" %c", d, 0x00B0, m, sec / 1000,
131 s.Printf(
"%03d%c %02ld' %02ld.%03ld\" %c", d, 0x00B0, m, sec / 1000,
133 else if (NEflag == 1)
134 s.Printf(
"%02d%c %02ld' %02ld.%ld\" %c", d, 0x00B0, m, sec / 10,
137 s.Printf(
"%03d%c %02ld' %02ld.%ld\" %c", d, 0x00B0, m, sec / 10,
148double toUsrSpeed(
double kts_speed,
int unit) {
156 ret = kts_speed * 1.15078;
159 ret = kts_speed * 1.852;
162 ret = kts_speed * 0.514444444;
171double toUsrWindSpeed(
double kts_wspeed,
int unit) {
173 if (
unit == -1)
unit = g_iWindSpeedFormat;
179 ret = kts_wspeed * 0.514444444;
182 ret = kts_wspeed * 1.15078;
185 ret = kts_wspeed * 1.852;
199 ret = nm_distance * 1.15078;
202 ret = nm_distance * 1.852;
205 ret = nm_distance * 1852;
208 ret = nm_distance * 6076.12;
211 ret = nm_distance * 1012.68591;
214 ret = nm_distance * 72913.4;
217 ret = nm_distance * 185200;
234 ret = (cel_temp * 9.0 / 5.0) + 32;
237 ret = cel_temp + 273.15;
246wxString getUsrTempUnit(
int unit) {
266wxString getUsrDistanceUnit(
int unit) {
301wxString getUsrSpeedUnit(
int unit) {
324wxString getUsrWindSpeedUnit(
int unit) {
326 if (
unit == -1)
unit = g_iWindSpeedFormat;
348 if (usrDistance < 0.1 &&
349 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI)) {
350 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
354 if (usrDistance < 5.0) {
356 }
else if (usrDistance < 100.0) {
358 }
else if (usrDistance < 1000.0) {
363 result << wxString::Format(format, usrDistance) << getUsrDistanceUnit(
unit);
370double fromUsrSpeed(
double usr_speed,
int unit,
int default_val) {
379 ret = usr_speed / 1.15078;
382 ret = usr_speed / 1.852;
385 ret = usr_speed / 0.514444444;
405 ret = usr_distance / 1.15078;
408 ret = usr_distance / 1.852;
411 ret = usr_distance / 1852;
414 ret = usr_distance / 6076.12;
417 ret = usr_distance / 1012.68591;
420 ret = usr_distance / 72913.4;
423 ret = usr_distance / 185200;
434 ret = m_depth / 0.3048;
440 ret = m_depth / 0.3048 / 6;
449double fromUsrDepth(
double usr_depth,
int unit) {
454 ret = usr_depth * 0.3048;
460 ret = usr_depth * 0.3048 * 6;
469wxString getUsrDepthUnit(
int unit) {
494 ret = m_height / 0.3048;
508 ret = usr_height * 0.3048;
531double vGetLengthOfNormal(pVector2D a, pVector2D b, pVector2D n) {
540 c.x = b->x * (vDotProduct(a, b) / vDotProduct(b, b));
541 c.y = b->y * (vDotProduct(a, b) / vDotProduct(b, b));
545 vSubtractVectors(a, &c, &vNormal);
551 return (vVectorMagnitude(&vNormal));
554double vDotProduct(pVector2D v0, pVector2D v1) {
558 (v0 == NULL || v1 == NULL) ? 0.0 : (v0->x * v1->x) + (v0->y * v1->y);
563pVector2D vAddVectors(pVector2D v0, pVector2D v1, pVector2D v) {
564 if (v0 == NULL || v1 == NULL)
567 v->x = v0->x + v1->x;
568 v->y = v0->y + v1->y;
573pVector2D vSubtractVectors(pVector2D v0, pVector2D v1, pVector2D v) {
574 if (v0 == NULL || v1 == NULL)
577 v->x = v0->x - v1->x;
578 v->y = v0->y - v1->y;
583double vVectorSquared(pVector2D v0) {
589 dS = ((v0->x * v0->x) + (v0->y * v0->y));
593double vVectorMagnitude(pVector2D v0) {
599 dMagnitude = sqrt(vVectorSquared(v0));
604 long sign, hrs_west, mins_west;
608 while (isspace(*datetime)) datetime++;
611 if (*datetime ==
'-') datetime++;
614 if ((end = dt.ParseFormat(datetime,
"%Y-%m-%dT%T")) != NULL) {
616 if (*end == 0)
return NULL;
622 else if (*end ==
'Z') {
628 else if (*end ==
'+' || *end ==
'-') {
637 if (isdigit(*end) && isdigit(*(end + 1)) && *(end + 2) ==
':') {
639 wxString(end).ToLong(&hrs_west);
640 if (hrs_west > 12)
return NULL;
644 if (isdigit(*end) && isdigit(*(end + 1))) {
648 mins[1] = *(end + 1);
650 wxString(mins).ToLong(&mins_west);
651 if (mins_west > 59)
return NULL;
654 dt -= sign * wxTimeSpan(hrs_west, mins_west, 0, 0);
671wxString formatTimeDelta(wxTimeSpan span) {
677 if (span.GetHours() > 0) span = RoundToMinutes(span);
678 if (span.GetDays() > 0) ss << setw(2) << span.GetDays() <<
"d ";
679 if (span.GetHours() > 0) {
680 ss << setw(2) << span.GetHours() % 24 << _(
"H ");
681 ss << setw(2) << span.GetMinutes() % 60 << _(
"M");
683 ss << setw(2) << span.GetMinutes() % 60 << _(
"M ");
684 ss << setw(2) << span.GetSeconds() % 60 << _(
"S");
689wxString formatTimeDelta(wxDateTime startTime, wxDateTime endTime) {
691 if (startTime.IsValid() && endTime.IsValid()) {
692 wxTimeSpan span = endTime - startTime;
693 return formatTimeDelta(span);
699wxString formatTimeDelta(wxLongLong secs) {
702 wxTimeSpan span(0, 0, secs);
703 return formatTimeDelta(span);
728double fromDMM(wxString sdms) {
732 double stk[32], sign = 1;
737 replhelper = wxString::FromUTF8(
"´·");
738 sdms.Replace(replhelper,
".");
740 wxString::FromUTF8(
"\"·");
741 sdms.Replace(replhelper,
".");
742 replhelper = wxString::FromUTF8(
"·");
743 sdms.Replace(replhelper,
".");
746 wxString::FromUTF8(
"s. š.");
748 sdms.Replace(replhelper,
"N");
749 replhelper = wxString::FromUTF8(
"j. š.");
750 sdms.Replace(replhelper,
"S");
751 sdms.Replace(
"v. d.",
"E");
752 sdms.Replace(
"z. d.",
"W");
757 if (sdms.Contains(
"N") || sdms.Contains(
"S") || sdms.Contains(
"E") ||
759 sdms.Replace(
"-",
" ");
761 wcsncpy(buf, sdms.wc_str(wxConvUTF8), 63);
763 len = wxMin(wcslen(buf),
sizeof(narrowbuf) - 1);
766 for (i = 0; i < len; i++) {
768 if ((c >=
'0' && c <=
'9') || c ==
'-' || c ==
'.' || c ==
'+') {
776 if ((c | 32) ==
'w' || (c | 32) ==
's')
782 stk[0] = stk[1] = stk[2] = 0;
783 for (i = 0; i < len; i++) {
784 while (i < len && narrowbuf[i] == 0) i++;
786 stk[top++] = atof(narrowbuf + i);
787 i += strlen(narrowbuf + i);
791 return sign * (stk[0] + (stk[1] + stk[2] / 60) / 60);
794double toMagnetic(
double deg_true) {
795 if (!std::isnan(
gVar)) {
796 if ((deg_true -
gVar) > 360.)
797 return (deg_true -
gVar - 360.);
799 return ((deg_true -
gVar) >= 0.) ? (deg_true -
gVar)
800 : (deg_true -
gVar + 360.);
802 if ((deg_true - g_UserVar) > 360.)
803 return (deg_true - g_UserVar - 360.);
805 return ((deg_true - g_UserVar) >= 0.) ? (deg_true - g_UserVar)
806 : (deg_true - g_UserVar + 360.);
810double toMagnetic(
double deg_true,
double variation) {
811 double degm = deg_true - variation;
815 return degm >= 0. ? degm : degm + 360.;
819wxString SanitizeFileName(
const wxString &input) {
821 static const wxString invalidChars =
"<>:\"/\\|?*";
823 for (wxUniChar ch : input) {
824 if (invalidChars.Contains(ch))
int g_iTempFormat
User-selected temperature unit format for display and input.
int g_iHeightFormat
User-selected height (vertical, above reference datum) unit format for display and input.
int g_nDepthUnitDisplay
User-selected depth (below surface) unit format for display and input.
int g_iSpeedFormat
User-selected speed unit format for display and input.
int g_iDistanceFormat
User-selected distance (horizontal) unit format for display and input.
const wxChar * ParseGPXDateTime(wxDateTime &dt, const wxChar *datetime)
This function parses a string containing a GPX time representation and returns a wxDateTime containin...
wxString getUsrHeightUnit(int unit)
Get the abbreviation for the preferred height unit.
double toUsrHeight(double m_height, int unit)
Convert height from meters to preferred height units.
double fromUsrDistance(double usr_distance, int unit, int default_val)
Convert distance from user units to nautical miles.
double fromUsrHeight(double usr_height, int unit)
Convert height from preferred height units to meters.
double toUsrDepth(double m_depth, int unit)
Convert a depth from meters to user display units.
double toUsrTemp(double cel_temp, int unit)
Convert a temperature from Celsius to user display units.
double toUsrDistance(double nm_distance, int unit)
Convert a distance from nautical miles (NMi) to user display units.
wxString FormatDistanceAdaptive(double distance)
Format a distance (given in nautical miles) using the current distance preference,...
Navigation Utility Functions without GUI dependencies.
double gVar
Magnetic variation in degrees.
Position, course, speed, etc.