24 #include "TCDS_Binary_Harmonic.h"
32 static const char *tz_names[][2] = {
67 typedef unsigned short WORD;
84 WCHAR StandardName[32];
87 WCHAR DaylightName[32];
107 tz_info_entry tz_info_local, tz_info_remote, *tz_info = &tz_info_local;
113 char *tz_time2sec(
char *psrc,
long *timesec) {
118 while (*psrc ==
' ') psrc++;
119 if (*psrc ==
'+') psrc++;
128 while (isdigit(*psrc)) temp = temp * 10 + (*(psrc++) -
'0');
130 *timesec = *timesec + temp * mpy;
136 }
while (isdigit(*psrc));
138 if (neg) *timesec = 0 - *timesec;
147 static char *tz_parse_name(
char *psrc,
char *pdst,
int maxlen) {
151 while (*psrc ==
' ') psrc++;
153 while (isalpha(*psrc) && nReturn < maxlen) {
154 *(pdst++) = *(psrc++);
165 static char *tz_parse_rule(
char *psrc,
SYSTEMTIME *st) {
166 int mol[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
168 if (*psrc ==
',') psrc++;
170 while (*psrc ==
' ') psrc++;
179 st->wMilliseconds = 0;
184 while (isdigit(*psrc)) temp = temp * 10 + (*(psrc++) -
'0');
186 if (temp < 1 || temp > 365)
return (0);
188 for (mo = 0; temp >= mol[mo]; mo++) temp -= mol[mo];
194 else if (*psrc ==
'M') {
198 while (isdigit(*psrc)) temp = temp * 10 + (*(psrc++) -
'0');
199 if (temp < 1 || temp > 12 || *psrc !=
'.')
return (0);
200 st->wMonth = (
unsigned short)temp;
204 while (isdigit(*psrc))
205 temp = temp * 10 + (*(psrc++) -
'0');
206 if (temp < 1 || temp > 5 || *psrc !=
'.')
return (0);
207 st->wDay = (
unsigned short)temp;
211 while (isdigit(*psrc))
212 temp = temp * 10 + (*(psrc++) -
'0');
213 if (temp < 0 || temp > 6)
return (0);
214 st->wDayOfWeek = (
unsigned short)temp;
219 psrc = tz_time2sec(psrc, &temp);
220 if (temp < 0 || temp >= 86400)
return (0);
221 st->wHour = temp / 3600;
223 st->wMinute = temp / 60;
224 st->wSecond = temp % 60;
232 static void tz_load_rule(
char *prule,
tz_info_entry *tz_info_remote) {
233 prule = tz_parse_name(prule, (
char *)tz_info_remote->tzi.StandardName, 30);
234 prule = tz_time2sec(prule, &tz_info_remote->tzi.Bias);
235 tz_info_remote->tzi.Bias /= 60;
236 tz_info_remote->tzi.StandardBias = 0;
238 prule = tz_parse_name(prule, (
char *)tz_info_remote->tzi.DaylightName, 30);
239 if (*(
char *)tz_info_remote->tzi.DaylightName !=
'\0') {
240 prule = tz_time2sec(prule, &tz_info_remote->tzi.DaylightBias);
241 tz_info_remote->tzi.DaylightBias /= 60;
242 if (tz_info_remote->tzi.DaylightBias == 0)
243 tz_info_remote->tzi.DaylightBias = -60;
245 tz_info_remote->tzi.DaylightBias -= tz_info_remote->tzi.Bias;
248 prule = tz_parse_rule(prule, &tz_info_remote->tzi.DaylightDate);
249 if (prule && *prule ==
',')
250 tz_parse_rule(prule, &tz_info_remote->tzi.StandardDate);
252 tz_parse_rule((
char *)
"M10.5.0/02:00:00",
253 &tz_info_remote->tzi.StandardDate);
255 tz_parse_rule((
char *)
"M4.1.0/02:00:00",
256 &tz_info_remote->tzi.DaylightDate);
257 tz_parse_rule((
char *)
"M10.5.0/02:00:00",
258 &tz_info_remote->tzi.StandardDate);
261 tz_info_remote->tzi.DaylightDate.wMonth = 0;
262 tz_info_remote->isdst = 0;
267 static void change_time_zone(
const char *tz) {
271 if (*tz ==
':') tz++;
275 if (tz_names[index][0] == NULL) {
276 tz_info = &tz_info_local;
280 if (!strcmp(tz_names[index][0], (tz))) {
282 strncpy(tz, tz_names[index][1], 39);
283 tz_load_rule(tz, &tz_info_remote);
284 tz_info = &tz_info_remote;
286 tz_info->year_beg = 0;
287 tz_info->year_end = 0;
295 TCDS_Binary_Harmonic::TCDS_Binary_Harmonic() {
308 TCDS_Binary_Harmonic::~TCDS_Binary_Harmonic()
310 for (
int i = 0; i < num_csts; i++) {
311 free(m_cst_nodes[i]);
312 free(m_cst_epochs[i]);
320 TC_Error_Code TCDS_Binary_Harmonic::LoadData(
const wxString &data_file_path) {
321 if (!open_tide_db(data_file_path.mb_str()))
return TC_TCD_FILE_CORRUPT;
327 source_ident = wxString(hdr.version, wxConvUTF8);
329 num_csts = hdr.constituents;
330 if (0 == num_csts)
return TC_GENERIC_ERROR;
332 num_nodes = hdr.number_of_years;
333 if (0 == num_nodes)
return TC_GENERIC_ERROR;
336 m_work_buffer = (
double *)malloc(num_csts *
sizeof(
double));
339 m_cst_speeds = (
double *)malloc(num_csts *
sizeof(
double));
341 for (
int a = 0; a < num_csts; a++) {
342 m_cst_speeds[a] = get_speed(a);
343 m_cst_speeds[a] *= M_PI / 648000;
347 m_first_year = hdr.start_year;
348 num_epochs = hdr.number_of_years;
350 m_cst_epochs = (
double **)malloc(num_csts *
sizeof(
double *));
351 for (
int i = 0; i < num_csts; i++)
352 m_cst_epochs[i] = (
double *)malloc(num_epochs *
sizeof(
double));
354 for (
int i = 0; i < num_csts; i++) {
355 for (
int year = 0; year < num_epochs; year++) {
356 m_cst_epochs[i][year] = get_equilibrium(i, year);
357 m_cst_epochs[i][year] *= M_PI / 180.0;
363 m_cst_nodes = (
double **)malloc(num_csts *
sizeof(
double *));
364 for (
int a = 0; a < num_csts; a++)
365 m_cst_nodes[a] = (
double *)malloc(num_nodes *
sizeof(
double));
367 for (
int a = 0; a < num_csts; a++) {
368 for (
int year = 0; year < num_nodes; year++)
369 m_cst_nodes[a][year] = get_node_factor(a, year);
375 for (
unsigned int i = 0; i < hdr.number_of_records; i++) {
376 read_tide_record(i, ptiderec);
380 pIDX->source_data_type = SOURCE_TYPE_BINARY_HARMONIC;
381 pIDX->pDataSource = NULL;
385 pIDX->pref_sta_data = NULL;
386 pIDX->IDX_Useable = 1;
387 pIDX->IDX_tzname = NULL;
389 pIDX->IDX_lon = ptiderec->header.longitude;
390 pIDX->IDX_lat = ptiderec->header.latitude;
392 const char *tz = get_tzfile(ptiderec->header.tzfile);
393 change_time_zone((
char *)tz);
394 if (tz_info) pIDX->IDX_time_zone = -tz_info->tzi.Bias;
396 strncpy(pIDX->IDX_station_name, ptiderec->header.name, MAXNAMELEN);
400 std::string name(ptiderec->header.name);
401 size_t n = name.find(
"depth");
402 if (n != std::string::npos) {
403 std::string d = name.substr(n);
404 std::string dp = d.substr(6);
405 size_t nd = dp.find_first_of(
' ');
406 std::string sval = dp.substr(0, nd);
407 int depth = std::stoi(sval);
408 pIDX->current_depth = depth;
411 pIDX->IDX_flood_dir = ptiderec->max_direction;
412 pIDX->IDX_ebb_dir = ptiderec->min_direction;
414 if (REFERENCE_STATION == ptiderec->header.record_type) {
416 wxString caplin(pIDX->IDX_station_name, wxConvUTF8);
418 if (caplin.Contains(_T(
"CURRENT")))
419 pIDX->IDX_type =
'C';
421 pIDX->IDX_type =
'T';
423 int t1 = ptiderec->zone_offset;
424 double zone_offset = (double)(t1 / 100) + ((double)(t1 % 100)) / 60.;
427 pIDX->IDX_ht_time_off = pIDX->IDX_lt_time_off = 0;
428 pIDX->IDX_ht_mpy = pIDX->IDX_lt_mpy = 1.0;
429 pIDX->IDX_ht_off = pIDX->IDX_lt_off = 0.0;
430 pIDX->IDX_ref_dbIndex = ptiderec->header.reference_station;
436 psd->amplitude = (
double *)malloc(num_csts *
sizeof(
double));
437 psd->epoch = (
double *)malloc(num_csts *
sizeof(
double));
438 psd->station_name = (
char *)malloc(ONELINER_LENGTH);
440 strncpy(psd->station_name, ptiderec->header.name, MAXNAMELEN);
441 psd->station_type = pIDX->IDX_type;
445 psd->meridian = -(tz_info->tzi.Bias * 60);
446 psd->zone_offset = zone_offset;
449 strncpy(psd->unit, get_level_units(ptiderec->level_units), 40 - 1);
450 psd->unit[40 - 1] =
'\0';
452 psd->have_BOGUS = (findunit(psd->unit) != -1) &&
453 (known_units[findunit(psd->unit)].type == BOGUS);
457 unit_c = findunit(
"knots");
459 unit_c = findunit(psd->unit);
462 strncpy(psd->units_conv, known_units[unit_c].name,
463 sizeof(psd->units_conv) - 1);
464 strncpy(psd->units_abbrv, known_units[unit_c].abbrv,
465 sizeof(psd->units_abbrv) - 1);
467 strncpy(psd->units_conv, psd->unit, 40 - 1);
468 psd->units_conv[40 - 1] =
'\0';
469 strncpy(psd->units_abbrv, psd->unit, 20 - 1);
470 psd->units_abbrv[20 - 1] =
'\0';
474 for (
int a = 0; a < num_csts; a++) {
475 psd->amplitude[a] = ptiderec->amplitude[a];
476 psd->epoch[a] = ptiderec->epoch[a] * M_PI / 180.;
479 psd->DATUM = ptiderec->datum_offset;
481 m_msd_array.Add(psd);
482 pIDX->pref_sta_data = psd;
483 pIDX->IDX_ref_dbIndex = i;
484 pIDX->have_offsets = 0;
485 }
else if (SUBORDINATE_STATION == ptiderec->header.record_type) {
487 wxString caplin(pIDX->IDX_station_name, wxConvUTF8);
489 if (caplin.Contains(_T(
"CURRENT")))
490 pIDX->IDX_type =
'c';
492 pIDX->IDX_type =
't';
494 int t1 = ptiderec->max_time_add;
495 double t1a = (double)(t1 / 100) + ((double)(t1 % 100)) / 60.;
497 pIDX->IDX_ht_time_off = t1a;
498 pIDX->IDX_ht_mpy = ptiderec->max_level_multiply;
499 if (0. == pIDX->IDX_ht_mpy) pIDX->IDX_ht_mpy = 1.0;
500 pIDX->IDX_ht_off = ptiderec->max_level_add;
502 t1 = ptiderec->min_time_add;
503 t1a = (double)(t1 / 100) + ((double)(t1 % 100)) / 60.;
505 pIDX->IDX_lt_time_off = t1a;
506 pIDX->IDX_lt_mpy = ptiderec->min_level_multiply;
507 if (0. == pIDX->IDX_lt_mpy) pIDX->IDX_lt_mpy = 1.0;
508 pIDX->IDX_lt_off = ptiderec->min_level_add;
510 pIDX->IDX_ref_dbIndex = ptiderec->header.reference_station;
514 if (pIDX->IDX_ht_time_off || pIDX->IDX_ht_off != 0.0 ||
515 pIDX->IDX_lt_off != 0.0 || pIDX->IDX_ht_mpy != 1.0 ||
516 pIDX->IDX_lt_mpy != 1.0)
517 pIDX->have_offsets = 1;
520 m_IDX_array.Add(pIDX);
524 unsigned int max_index = GetMaxIndex();
525 for (
unsigned int i = 0; i < max_index; i++) {
528 pIDX->num_nodes = num_nodes;
529 pIDX->num_csts = num_csts;
530 pIDX->num_epochs = num_epochs;
531 pIDX->m_cst_speeds = m_cst_speeds;
532 pIDX->m_cst_nodes = m_cst_nodes;
533 pIDX->m_cst_epochs = m_cst_epochs;
534 pIDX->first_year = m_first_year;
535 pIDX->m_work_buffer = m_work_buffer;
543 IDX_entry *TCDS_Binary_Harmonic::GetIndexEntry(
int n_index) {
544 return &m_IDX_array[n_index];
547 TC_Error_Code TCDS_Binary_Harmonic::LoadHarmonicData(
IDX_entry *pIDX) {
549 if (!strlen(pIDX->IDX_reference_name)) {
550 strncpy(pIDX->IDX_reference_name, get_station(pIDX->IDX_ref_dbIndex),
552 pIDX->IDX_reference_name[MAXNAMELEN - 1] =
'\0';
558 IDX_entry *pIDX_Ref = &m_IDX_array.Item(pIDX->IDX_ref_dbIndex);
560 pIDX->pref_sta_data = pRefSta;
561 pIDX->station_tz_offset =
562 -pRefSta->meridian + (pRefSta->zone_offset * 3600);