35static const char *tz_names[][2] = {
70typedef unsigned short WORD;
87 WCHAR StandardName[32];
90 WCHAR DaylightName[32];
110tz_info_entry tz_info_local, tz_info_remote, *tz_info = &tz_info_local;
116char *tz_time2sec(
char *psrc,
long *timesec) {
121 while (*psrc ==
' ') psrc++;
122 if (*psrc ==
'+') psrc++;
131 while (isdigit(*psrc)) temp = temp * 10 + (*(psrc++) -
'0');
133 *timesec = *timesec + temp * mpy;
139 }
while (isdigit(*psrc));
141 if (neg) *timesec = 0 - *timesec;
150static char *tz_parse_name(
char *psrc,
char *pdst,
int maxlen) {
154 while (*psrc ==
' ') psrc++;
156 while (isalpha(*psrc) && nReturn < maxlen) {
157 *(pdst++) = *(psrc++);
168static char *tz_parse_rule(
char *psrc,
SYSTEMTIME *st) {
169 int mol[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
171 if (*psrc ==
',') psrc++;
173 while (*psrc ==
' ') psrc++;
182 st->wMilliseconds = 0;
187 while (isdigit(*psrc)) temp = temp * 10 + (*(psrc++) -
'0');
189 if (temp < 1 || temp > 365)
return (0);
191 for (mo = 0; temp >= mol[mo]; mo++) temp -= mol[mo];
197 else if (*psrc ==
'M') {
201 while (isdigit(*psrc)) temp = temp * 10 + (*(psrc++) -
'0');
202 if (temp < 1 || temp > 12 || *psrc !=
'.')
return (0);
203 st->wMonth = (
unsigned short)temp;
207 while (isdigit(*psrc))
208 temp = temp * 10 + (*(psrc++) -
'0');
209 if (temp < 1 || temp > 5 || *psrc !=
'.')
return (0);
210 st->wDay = (
unsigned short)temp;
214 while (isdigit(*psrc))
215 temp = temp * 10 + (*(psrc++) -
'0');
216 if (temp < 0 || temp > 6)
return (0);
217 st->wDayOfWeek = (
unsigned short)temp;
222 psrc = tz_time2sec(psrc, &temp);
223 if (temp < 0 || temp >= 86400)
return (0);
224 st->wHour = temp / 3600;
226 st->wMinute = temp / 60;
227 st->wSecond = temp % 60;
235static void tz_load_rule(
char *prule,
tz_info_entry *tz_info_remote) {
236 prule = tz_parse_name(prule, (
char *)tz_info_remote->tzi.StandardName, 30);
237 prule = tz_time2sec(prule, &tz_info_remote->tzi.Bias);
238 tz_info_remote->tzi.Bias /= 60;
239 tz_info_remote->tzi.StandardBias = 0;
241 prule = tz_parse_name(prule, (
char *)tz_info_remote->tzi.DaylightName, 30);
242 if (*(
char *)tz_info_remote->tzi.DaylightName !=
'\0') {
243 prule = tz_time2sec(prule, &tz_info_remote->tzi.DaylightBias);
244 tz_info_remote->tzi.DaylightBias /= 60;
245 if (tz_info_remote->tzi.DaylightBias == 0)
246 tz_info_remote->tzi.DaylightBias = -60;
248 tz_info_remote->tzi.DaylightBias -= tz_info_remote->tzi.Bias;
251 prule = tz_parse_rule(prule, &tz_info_remote->tzi.DaylightDate);
252 if (prule && *prule ==
',')
253 tz_parse_rule(prule, &tz_info_remote->tzi.StandardDate);
255 tz_parse_rule((
char *)
"M10.5.0/02:00:00",
256 &tz_info_remote->tzi.StandardDate);
258 tz_parse_rule((
char *)
"M4.1.0/02:00:00",
259 &tz_info_remote->tzi.DaylightDate);
260 tz_parse_rule((
char *)
"M10.5.0/02:00:00",
261 &tz_info_remote->tzi.StandardDate);
264 tz_info_remote->tzi.DaylightDate.wMonth = 0;
265 tz_info_remote->isdst = 0;
270static void change_time_zone(
const char *tz) {
274 if (*tz ==
':') tz++;
278 if (tz_names[index][0] == NULL) {
279 tz_info = &tz_info_local;
283 if (!strcmp(tz_names[index][0], (tz))) {
285 strncpy(tz, tz_names[index][1], 39);
286 tz_load_rule(tz, &tz_info_remote);
287 tz_info = &tz_info_remote;
289 tz_info->year_beg = 0;
290 tz_info->year_end = 0;
298TCDS_Binary_Harmonic::TCDS_Binary_Harmonic() {
308 m_work_buffer =
nullptr;
309 m_cst_epochs =
nullptr;
310 m_cst_nodes =
nullptr;
311 m_cst_speeds =
nullptr;
314TCDS_Binary_Harmonic::~TCDS_Binary_Harmonic() {
315 for (
int i = 0; i < num_csts; i++) {
316 free(m_cst_nodes[i]);
317 free(m_cst_epochs[i]);
325TC_Error_Code TCDS_Binary_Harmonic::LoadData(
const wxString &data_file_path) {
327 if (!open_tide_db(data_file_path.mb_str()))
return TC_TCD_FILE_CORRUPT;
329 return TC_TCD_FILE_CORRUPT;
336 source_ident = wxString(hdr.version, wxConvUTF8);
338 num_csts = hdr.constituents;
339 if (0 == num_csts)
return TC_GENERIC_ERROR;
341 num_nodes = hdr.number_of_years;
342 if (0 == num_nodes)
return TC_GENERIC_ERROR;
345 m_work_buffer = (
double *)malloc(num_csts *
sizeof(
double));
348 m_cst_speeds = (
double *)malloc(num_csts *
sizeof(
double));
350 for (
int a = 0; a < num_csts; a++) {
351 m_cst_speeds[a] = get_speed(a);
352 m_cst_speeds[a] *= M_PI / 648000;
356 m_first_year = hdr.start_year;
357 num_epochs = hdr.number_of_years;
359 m_cst_epochs = (
double **)malloc(num_csts *
sizeof(
double *));
360 for (
int i = 0; i < num_csts; i++)
361 m_cst_epochs[i] = (
double *)malloc(num_epochs *
sizeof(
double));
363 for (
int i = 0; i < num_csts; i++) {
364 for (
int year = 0; year < num_epochs; year++) {
365 m_cst_epochs[i][year] = get_equilibrium(i, year);
366 m_cst_epochs[i][year] *= M_PI / 180.0;
371 unsigned nodes_size = num_csts *
sizeof(
double *);
373 assert(nodes_size < PTRDIFF_MAX);
375 m_cst_nodes = (
double **)malloc(nodes_size);
376 for (
int a = 0; a < num_csts; a++)
377 m_cst_nodes[a] = (
double *)malloc(num_nodes *
sizeof(
double));
379 for (
int a = 0; a < num_csts; a++) {
380 for (
int year = 0; year < num_nodes; year++)
381 m_cst_nodes[a][year] = get_node_factor(a, year);
387 for (
unsigned int i = 0; i < hdr.number_of_records; i++) {
388 read_tide_record(i, ptiderec);
401 pIDX->
IDX_lon = ptiderec->header.longitude;
402 pIDX->
IDX_lat = ptiderec->header.latitude;
404 const char *tz = get_tzfile(ptiderec->header.tzfile);
405 change_time_zone((
char *)tz);
412 std::string name(ptiderec->header.name);
413 size_t n = name.find(
"depth");
414 if (n != std::string::npos) {
415 std::string d = name.substr(n);
416 std::string dp = d.substr(6);
417 size_t nd = dp.find_first_of(
' ');
418 std::string sval = dp.substr(0, nd);
419 int depth = std::stoi(sval);
426 if (REFERENCE_STATION == ptiderec->header.record_type) {
430 if (caplin.Contains(
"CURRENT"))
435 int t1 = ptiderec->zone_offset;
436 double zone_offset = (double)(t1 / 100) + ((double)(t1 % 100)) / 60.;
448 psd->amplitude = (
double *)malloc(num_csts *
sizeof(
double));
449 psd->epoch = (
double *)malloc(num_csts *
sizeof(
double));
450 psd->station_name = (
char *)malloc(ONELINER_LENGTH);
452 strncpy(psd->station_name, ptiderec->header.name, MAXNAMELEN);
457 psd->meridian = -(tz_info->tzi.Bias * 60);
458 psd->zone_offset = zone_offset;
461 strncpy(psd->unit, get_level_units(ptiderec->level_units), 40 - 1);
462 psd->unit[40 - 1] =
'\0';
464 psd->have_BOGUS = (findunit(psd->unit) != -1) &&
465 (known_units[findunit(psd->unit)].type == BOGUS);
469 unit_c = findunit(
"knots");
471 unit_c = findunit(psd->unit);
474 strncpy(psd->units_conv, known_units[unit_c].name,
475 sizeof(psd->units_conv) - 1);
476 strncpy(psd->units_abbrv, known_units[unit_c].abbrv,
477 sizeof(psd->units_abbrv) - 1);
479 memcpy(psd->units_conv, psd->unit, 40 - 1);
480 psd->units_conv[40 - 1] =
'\0';
481 memcpy(psd->units_abbrv, psd->unit, 20 - 1);
482 psd->units_abbrv[20 - 1] =
'\0';
486 for (
int a = 0; a < num_csts; a++) {
487 psd->amplitude[a] = ptiderec->amplitude[a];
488 psd->epoch[a] = ptiderec->epoch[a] * M_PI / 180.;
491 psd->DATUM = ptiderec->datum_offset;
493 m_msd_array.Add(psd);
497 }
else if (SUBORDINATE_STATION == ptiderec->header.record_type) {
501 if (caplin.Contains(
"CURRENT"))
506 int t1 = ptiderec->max_time_add;
507 double t1a = (double)(t1 / 100) + ((double)(t1 % 100)) / 60.;
510 pIDX->
IDX_ht_mpy = ptiderec->max_level_multiply;
514 t1 = ptiderec->min_time_add;
515 t1a = (double)(t1 / 100) + ((double)(t1 % 100)) / 60.;
518 pIDX->
IDX_lt_mpy = ptiderec->min_level_multiply;
532 m_IDX_array.Add(pIDX);
536 unsigned int max_index = GetMaxIndex();
537 for (
unsigned int i = 0; i < max_index; i++) {
555IDX_entry *TCDS_Binary_Harmonic::GetIndexEntry(
int n_index) {
556 return &m_IDX_array[n_index];
559TC_Error_Code TCDS_Binary_Harmonic::LoadHarmonicData(
IDX_entry *pIDX) {
574 -pRefSta->meridian + (pRefSta->zone_offset * 3600);
Represents an index entry for tidal and current data.
int have_offsets
Flag indicating presence of time/height offsets.
int IDX_time_zone
Station timezone offset from UTC (in minutes)
char IDX_type
Entry type identifier "TCtcIUu".
int num_nodes
Number of nodes in harmonic analysis.
float IDX_lt_off
Low tide height offset.
TCDataSource * pDataSource
Pointer to the associated data source.
float IDX_lt_mpy
Low tide height multiplier.
char IDX_reference_name[MAXNAMELEN]
Name of the reference station.
int Valid15
Validity flag for 15-minute interval data.
int IDX_flood_dir
Flood current direction (in degrees)
int IDX_ref_dbIndex
Database index of the reference station.
int IDX_Useable
Flag indicating if the entry is usable.
char IDX_station_name[MAXNAMELEN]
Name of the tidal or current station.
int station_tz_offset
Offset in seconds to convert from harmonic data (epochs) to the station time zone.
int first_year
First year of valid data.
double * m_work_buffer
Work buffer for calculations.
int IDX_ht_time_off
High tide time offset (in minutes)
source_data_t source_data_type
Format of the source data (ASCII or binary)
double ** m_cst_nodes
2D array of constituent nodes
int IDX_ebb_dir
Ebb current direction (in degrees)
double ** m_cst_epochs
2D array of constituent epochs
float IDX_ht_mpy
High tide height multiplier.
int current_depth
Depth for current stations.
double IDX_lat
Latitude of the station (in degrees, +North)
double IDX_lon
Longitude of the station (in degrees, +East)
int num_epochs
Number of epochs in harmonic data.
double * m_cst_speeds
Array of constituent speeds.
Station_Data * pref_sta_data
Pointer to the reference station data.
int IDX_lt_time_off
Low tide time offset (in minutes)
int num_csts
Number of harmonic constituents.
char * IDX_tzname
Timezone name (dynamically allocated)
float IDX_ht_off
High tide height offset.
@ SOURCE_TYPE_BINARY_HARMONIC
Binary harmonic source type.
TCDataFactory loading data from binary file.
Tide and Current Manager @TODO Add original author copyright.