33#include <wx/datetime.h>
36#include <wx/translation.h>
38#include "model/navutil_base.h"
39#include "model/own_ship.h"
43static wxTimeSpan RoundToMinutes(
const wxTimeSpan &span) {
44 auto minutes = span.GetMinutes() % 60;
45 auto seconds = span.GetSeconds() % 60;
46 if (seconds > 30) minutes += 1;
47 return wxTimeSpan(span.GetHours(), minutes, 0);
50wxString toSDMM(
int NEflag,
double a,
bool hi_precision) {
73 }
else if (NEflag == 2) {
83 switch (g_iSDMMFormat) {
86 if (hi_precision) mpy = mpy * 1000;
88 m = (long)wxRound((a - (
double)d) * mpy);
90 if (!NEflag || NEflag < 1 || NEflag > 2)
93 s.Printf(_T (
"%d%c %02ld.%04ld'" ), d, 0x00B0, m / 10000, m % 10000);
95 s.Printf(_T (
"%d%c %02ld.%01ld'" ), d, 0x00B0, m / 10, m % 10);
99 s.Printf(_T (
"%02d%c %02ld.%04ld' %c" ), d, 0x00B0, m / 10000,
102 s.Printf(_T (
"%03d%c %02ld.%04ld' %c" ), d, 0x00B0, m / 10000,
104 else if (NEflag == 1)
105 s.Printf(_T (
"%02d%c %02ld.%01ld' %c" ), d, 0x00B0, m / 10, (m % 10),
108 s.Printf(_T (
"%03d%c %02ld.%01ld' %c" ), d, 0x00B0, m / 10, (m % 10),
114 s.Printf(_T (
"%03.6f" ),
119 s.Printf(_T (
"%03.4f" ), ang);
122 m = (long)((a - (
double)d) * 60);
124 if (hi_precision) mpy = mpy * 100;
125 long sec = (long)((a - (
double)d - (((double)m) / 60)) * 3600 * mpy);
127 if (!NEflag || NEflag < 1 || NEflag > 2)
130 s.Printf(_T (
"%d%c %ld'%ld.%ld\"" ), d, 0x00B0, m, sec / 1000,
133 s.Printf(_T (
"%d%c %ld'%ld.%ld\"" ), d, 0x00B0, m, sec / 10,
138 s.Printf(_T (
"%02d%c %02ld' %02ld.%03ld\" %c" ), d, 0x00B0, m,
139 sec / 1000, sec % 1000, c);
141 s.Printf(_T (
"%03d%c %02ld' %02ld.%03ld\" %c" ), d, 0x00B0, m,
142 sec / 1000, sec % 1000, c);
143 else if (NEflag == 1)
144 s.Printf(_T (
"%02d%c %02ld' %02ld.%ld\" %c" ), d, 0x00B0, m,
145 sec / 10, sec % 10, c);
147 s.Printf(_T (
"%03d%c %02ld' %02ld.%ld\" %c" ), d, 0x00B0, m,
148 sec / 10, sec % 10, c);
158double toUsrSpeed(
double kts_speed,
int unit) {
160 if (
unit == -1)
unit = g_iSpeedFormat;
166 ret = kts_speed * 1.15078;
169 ret = kts_speed * 1.852;
172 ret = kts_speed * 0.514444444;
181double toUsrWindSpeed(
double kts_wspeed,
int unit) {
183 if (
unit == -1)
unit = g_iWindSpeedFormat;
189 ret = kts_wspeed * 0.514444444;
192 ret = kts_wspeed * 1.15078;
195 ret = kts_wspeed * 1.852;
204double toUsrDistance(
double nm_distance,
int unit) {
206 if (
unit == -1)
unit = g_iDistanceFormat;
212 ret = nm_distance * 1.15078;
215 ret = nm_distance * 1.852;
218 ret = nm_distance * 1852;
221 ret = nm_distance * 6076.12;
224 ret = nm_distance * 1012.68591;
227 ret = nm_distance * 72913.4;
230 ret = nm_distance * 185200;
239double toUsrTemp(
double cel_temp,
int unit) {
241 if (
unit == -1)
unit = g_iTempFormat;
247 ret = (cel_temp * 9.0 / 5.0) + 32;
250 ret = cel_temp + 273.15;
259wxString getUsrTempUnit(
int unit) {
261 if (
unit == -1)
unit = g_iTempFormat;
279wxString getUsrDistanceUnit(
int unit) {
281 if (
unit == -1)
unit = g_iDistanceFormat;
314wxString getUsrSpeedUnit(
int unit) {
316 if (
unit == -1)
unit = g_iSpeedFormat;
337wxString getUsrWindSpeedUnit(
int unit) {
339 if (
unit == -1)
unit = g_iWindSpeedFormat;
357wxString FormatDistanceAdaptive(
double distance) {
359 int unit = g_iDistanceFormat;
360 double usrDistance = toUsrDistance(distance,
unit);
361 if (usrDistance < 0.1 &&
362 (
unit == DISTANCE_KM ||
unit == DISTANCE_MI ||
unit == DISTANCE_NMI)) {
363 unit = (
unit == DISTANCE_MI) ? DISTANCE_FT : DISTANCE_M;
364 usrDistance = toUsrDistance(distance,
unit);
367 if (usrDistance < 5.0) {
368 format = _T(
"%1.2f ");
369 }
else if (usrDistance < 100.0) {
370 format = _T(
"%2.1f ");
371 }
else if (usrDistance < 1000.0) {
372 format = _T(
"%3.0f ");
374 format = _T(
"%4.0f ");
376 result << wxString::Format(format, usrDistance) << getUsrDistanceUnit(
unit);
383double fromUsrSpeed(
double usr_speed,
int unit,
int default_val) {
392 ret = usr_speed / 1.15078;
395 ret = usr_speed / 1.852;
398 ret = usr_speed / 0.514444444;
407double fromUsrDistance(
double usr_distance,
int unit,
int default_val) {
415 ret = usr_distance / 1.15078;
418 ret = usr_distance / 1.852;
421 ret = usr_distance / 1852;
424 ret = usr_distance / 6076.12;
433double toUsrDepth(
double cel_depth,
int unit) {
435 if (
unit == -1)
unit = g_nDepthUnitDisplay;
438 ret = cel_depth / 0.3048;
444 ret = cel_depth / 0.3048 / 6;
453double fromUsrDepth(
double usr_depth,
int unit) {
455 if (
unit == -1)
unit = g_nDepthUnitDisplay;
458 ret = usr_depth * 0.3048;
464 ret = usr_depth * 0.3048 * 6;
473wxString getUsrDepthUnit(
int unit) {
475 if (
unit == -1)
unit = g_nDepthUnitDisplay;
493double vGetLengthOfNormal(pVector2D a, pVector2D b, pVector2D n) {
502 c.x = b->x * (vDotProduct(a, b) / vDotProduct(b, b));
503 c.y = b->y * (vDotProduct(a, b) / vDotProduct(b, b));
507 vSubtractVectors(a, &c, &vNormal);
513 return (vVectorMagnitude(&vNormal));
516double vDotProduct(pVector2D v0, pVector2D v1) {
520 (v0 == NULL || v1 == NULL) ? 0.0 : (v0->x * v1->x) + (v0->y * v1->y);
525pVector2D vAddVectors(pVector2D v0, pVector2D v1, pVector2D v) {
526 if (v0 == NULL || v1 == NULL)
529 v->x = v0->x + v1->x;
530 v->y = v0->y + v1->y;
535pVector2D vSubtractVectors(pVector2D v0, pVector2D v1, pVector2D v) {
536 if (v0 == NULL || v1 == NULL)
539 v->x = v0->x - v1->x;
540 v->y = v0->y - v1->y;
545double vVectorSquared(pVector2D v0) {
551 dS = ((v0->x * v0->x) + (v0->y * v0->y));
555double vVectorMagnitude(pVector2D v0) {
561 dMagnitude = sqrt(vVectorSquared(v0));
565const wxChar *ParseGPXDateTime(wxDateTime &dt,
const wxChar *datetime) {
566 long sign, hrs_west, mins_west;
570 while (isspace(*datetime)) datetime++;
573 if (*datetime == wxT(
'-')) datetime++;
576 if ((end = dt.ParseFormat(datetime, wxT(
"%Y-%m-%dT%T"))) != NULL) {
578 if (*end == 0)
return NULL;
584 else if (*end == wxT(
'Z')) {
590 else if (*end == wxT(
'+') || *end == wxT(
'-')) {
592 if (*end == wxT(
'+'))
599 if (isdigit(*end) && isdigit(*(end + 1)) && *(end + 2) == wxT(
':')) {
601 wxString(end).ToLong(&hrs_west);
602 if (hrs_west > 12)
return NULL;
606 if (isdigit(*end) && isdigit(*(end + 1))) {
610 mins[1] = *(end + 1);
612 wxString(mins).ToLong(&mins_west);
613 if (mins_west > 59)
return NULL;
616 dt -= sign * wxTimeSpan(hrs_west, mins_west, 0, 0);
633wxString formatTimeDelta(wxTimeSpan span) {
639 if (span.GetHours() > 0) span = RoundToMinutes(span);
640 if (span.GetDays() > 0) ss << setw(2) << span.GetDays() <<
"d ";
641 if (span.GetHours() > 0) {
642 ss << setw(2) << span.GetHours() % 24 << _(
"H ");
643 ss << setw(2) << span.GetMinutes() % 60 << _(
"M");
645 ss << setw(2) << span.GetMinutes() % 60 << _(
"M ");
646 ss << setw(2) << span.GetSeconds() % 60 << _(
"S");
651wxString formatTimeDelta(wxDateTime startTime, wxDateTime endTime) {
653 if (startTime.IsValid() && endTime.IsValid()) {
654 wxTimeSpan span = endTime - startTime;
655 return formatTimeDelta(span);
661wxString formatTimeDelta(wxLongLong secs) {
664 wxTimeSpan span(0, 0, secs);
665 return formatTimeDelta(span);
690double fromDMM(wxString sdms) {
694 double stk[32], sign = 1;
699 replhelper = wxString::FromUTF8(
"´·");
700 sdms.Replace(replhelper, _T(
"."));
702 wxString::FromUTF8(
"\"·");
703 sdms.Replace(replhelper, _T(
"."));
704 replhelper = wxString::FromUTF8(
"·");
705 sdms.Replace(replhelper, _T(
"."));
708 wxString::FromUTF8(
"s. š.");
710 sdms.Replace(replhelper, _T(
"N"));
711 replhelper = wxString::FromUTF8(
"j. š.");
712 sdms.Replace(replhelper, _T(
"S"));
713 sdms.Replace(_T(
"v. d."), _T(
"E"));
714 sdms.Replace(_T(
"z. d."), _T(
"W"));
719 if (sdms.Contains(_T(
"N")) || sdms.Contains(_T(
"S")) ||
720 sdms.Contains(_T(
"E")) || sdms.Contains(_T(
"W")))
721 sdms.Replace(_T(
"-"), _T(
" "));
723 wcsncpy(buf, sdms.wc_str(wxConvUTF8), 63);
725 len = wxMin(wcslen(buf),
sizeof(narrowbuf) - 1);
728 for (i = 0; i < len; i++) {
730 if ((c >=
'0' && c <=
'9') || c ==
'-' || c ==
'.' || c ==
'+') {
738 if ((c | 32) ==
'w' || (c | 32) ==
's')
744 stk[0] = stk[1] = stk[2] = 0;
745 for (i = 0; i < len; i++) {
746 while (i < len && narrowbuf[i] == 0) i++;
748 stk[top++] = atof(narrowbuf + i);
749 i += strlen(narrowbuf + i);
753 return sign * (stk[0] + (stk[1] + stk[2] / 60) / 60);
756double toMagnetic(
double deg_true) {
757 if (!std::isnan(gVar)) {
758 if ((deg_true - gVar) > 360.)
759 return (deg_true - gVar - 360.);
761 return ((deg_true - gVar) >= 0.) ? (deg_true - gVar)
762 : (deg_true - gVar + 360.);
764 if ((deg_true - g_UserVar) > 360.)
765 return (deg_true - g_UserVar - 360.);
767 return ((deg_true - g_UserVar) >= 0.) ? (deg_true - g_UserVar)
768 : (deg_true - g_UserVar + 360.);
772double toMagnetic(
double deg_true,
double variation) {
773 double degm = deg_true - variation;
777 return degm >= 0. ? degm : degm + 360.;