27#include <wx/filename.h>
28#include <wx/tokenzr.h>
33#define M_PI ((2) * (acos(0.0)))
49static int hhmm2seconds(
char *hhmm) {
52 if (sscanf(hhmm,
"%d:%d", &h, &m) != 2)
return (0);
53 if (sscanf(hhmm,
"%c", &s) != 1)
return (0);
54 if (h < 0 || s ==
'-') m = -m;
55 return h * 3600 + m * 60;
58TCDS_Ascii_Harmonic::TCDS_Ascii_Harmonic() {
73TCDS_Ascii_Harmonic::~TCDS_Ascii_Harmonic() {
79TC_Error_Code TCDS_Ascii_Harmonic::LoadData(
const wxString &data_file_path) {
80 if (m_IndexFile) IndexFileIO(IFF_CLOSE, 0);
82 m_indexfile_name = data_file_path;
84 TC_Error_Code error_return = init_index_file();
85 if (error_return != TC_NO_ERROR)
return error_return;
87 wxFileName f(data_file_path);
88 m_harmfile_name = f.GetPath(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME);
89 m_harmfile_name += f.GetName();
90 error_return = LoadHarmonicConstants(m_harmfile_name);
93 unsigned int max_index = GetMaxIndex();
94 for (
unsigned int i = 0; i < max_index; i++) {
111IDX_entry *TCDS_Ascii_Harmonic::GetIndexEntry(
int n_index) {
112 return &m_IDX_array[n_index];
115TC_Error_Code TCDS_Ascii_Harmonic::init_index_file() {
116 long int xref_start = 0;
120 m_abbreviation_array.clear();
124 int index_in_memory = 0;
126 if (IndexFileIO(IFF_OPEN, 0)) {
127 while (IndexFileIO(IFF_READ, 0)) {
128 if ((index_line_buffer[0] ==
'#') || (index_line_buffer[0] <=
' '))
130 else if (!have_index && !xref_start) {
131 if (!strncmp(index_line_buffer,
"XREF", 4))
132 xref_start = IndexFileIO(IFF_TELL, 0);
133 }
else if (!have_index && !strncmp(index_line_buffer,
"*END*", 5)) {
134 if (m_abbreviation_array.empty()) {
135 IndexFileIO(IFF_CLOSE, 0);
136 return (TC_INDEX_FILE_CORRUPT);
144 else if (!have_index && xref_start) {
145 wxString line(index_line_buffer, wxConvUTF8);
149 wxStringTokenizer tkz(line,
" ");
150 wxString token = tkz.GetNextToken();
151 if (token.IsSameAs(
"REGION", FALSE))
153 else if (token.IsSameAs(
"COUNTRY", FALSE))
154 entry.type = COUNTRY;
155 else if (token.IsSameAs(
"STATE", FALSE))
158 token = tkz.GetNextToken();
159 entry.short_s = token;
161 entry.long_s = line.Mid(tkz.GetPosition()).Strip();
163 m_abbreviation_array.push_back(entry);
167 else if (have_index && (strchr(
"TtCcIUu", index_line_buffer[0]))) {
174 index_in_memory = TRUE;
177 if (TC_NO_ERROR != build_IDX_entry(pIDX)) {
180 m_IDX_array.Add(pIDX);
184 else if (have_index && (index_line_buffer[0] ==
'H')) {
186 sscanf(index_line,
"Harmonic %s", s1);
187 pHarmonic = harmonic_file_list;
188 while (pHarmonic && pHarmonic->next)
190 pHarmonic_prev = pHarmonic;
192 if (NULL == pHarmonic) {
194 free_harmonic_file_list();
197 if (!harmonic_file_list)
198 harmonic_file_list = pHarmonic;
199 else pHarmonic_prev->next = pHarmonic;
200 pHarmonic->next = NULL;
201 pHarmonic->rec_start = num_IDX;
202 if (allocate_copy_string(&pHarmonic->name,s1)) {
204 free_harmonic_file_list();
210 if (index_in_memory) IndexFileIO(IFF_CLOSE, 0);
215 return (TC_NO_ERROR);
222TC_Error_Code TCDS_Ascii_Harmonic::build_IDX_entry(
IDX_entry *pIDX) {
232 if (7 != sscanf(index_line_buffer,
"%c%s%lf%lf%d:%d%*c%[^\r\n]",
235 return (TC_INDEX_ENTRY_BAD);
237 if (TZHr < 0 && TZMin > 0)
243 index_line_buffer[0])) {
244 IndexFileIO(IFF_READ, 0);
246 if (index_line_buffer[0] ==
'^')
248 if (11 != sscanf(index_line_buffer,
249 "%*c%d %f %f %d %f %f %d %d %d %d%*c%[^\r\n]",
255 return (TC_INDEX_ENTRY_BAD);
270 if (9 != sscanf(index_line_buffer,
271 "%*c%d %f %f %d %f %f %d %d%*c%[^\r\n]",
278 if (10 != sscanf(index_line_buffer,
279 "%*c%d %f %f %d %f %f %d %s %d%*c%[^\r\n]",
285 return (TC_INDEX_ENTRY_BAD);
287 if (NULL != (pIDX->
IDX_tzname = (
char *)malloc(strlen(stz) + 1)))
327 return (TC_NO_ERROR);
331TC_Error_Code TCDS_Ascii_Harmonic::LoadHarmonicConstants(
332 const wxString &data_file_path) {
334 char linrec[linelen];
340 fp = fopen(data_file_path.mb_str(),
"r");
341 if (NULL == fp)
return TC_FILE_NOT_FOUND;
343 read_next_line(fp, linrec, 0);
345 if (1 != sscanf(linrec,
"%d", &num_csts))
goto error;
351 m_cst_speeds = (
double *)malloc(num_csts *
sizeof(
double));
352 m_work_buffer = (
double *)malloc(num_csts *
sizeof(
double));
355 for (a = 0; a < num_csts; a++) {
356 read_next_line(fp, linrec, 0);
357 sscanf(linrec,
"%s %lf", junk, &(m_cst_speeds[a]));
358 m_cst_speeds[a] *= M_PI / 648000;
362 read_next_line(fp, linrec, 0);
363 sscanf(linrec,
"%d", &m_first_year);
366 read_next_line(fp, linrec, 0);
367 if (1 != sscanf(linrec,
"%d", &num_epochs))
goto error;
368 if (num_epochs <= 0 || num_epochs > 1000000)
goto error;
370 m_cst_epochs = (
double **)malloc(num_csts *
sizeof(
double *));
371 for (
int i = 0; i < num_csts; i++)
372 m_cst_epochs[i] = (
double *)malloc(num_epochs *
sizeof(
double));
374 for (
int i = 0; i < num_csts; i++) {
375 if (1 != fscanf(fp,
"%s", linrec))
goto error;
376 for (
int b = 0; b < num_epochs; b++) {
377 if (1 != fscanf(fp,
"%lf", &(m_cst_epochs[i][b])))
goto error;
378 m_cst_epochs[i][b] *= M_PI / 180.0;
383 if (1 != fscanf(fp,
"%s", linrec))
goto error;
387 read_next_line(fp, linrec, 0);
388 if (1 != sscanf(linrec,
"%d", &num_nodes))
goto error;
389 if (num_nodes <= 0 || num_nodes > 1000000)
goto error;
391 m_cst_nodes = (
double **)malloc(num_csts *
sizeof(
double *));
392 for (
int a = 0; a < num_csts; a++)
393 m_cst_nodes[a] = (
double *)malloc(num_nodes *
sizeof(
double));
395 for (
int a = 0; a < num_csts; a++) {
396 int ignore = fscanf(fp,
"%s", linrec);
397 for (b = 0; b < num_nodes; b++)
398 ignore = fscanf(fp,
"%lf", &(m_cst_nodes[a][b]));
407 return TC_HARM_FILE_CORRUPT;
410TC_Error_Code TCDS_Ascii_Harmonic::LoadHarmonicData(
IDX_entry *pIDX) {
417 for (
unsigned int i = 0; i < m_msd_array.GetCount(); i++) {
418 psd = &m_msd_array[i];
428 (toupper(pIDX->
IDX_type) ==
static_cast<int>(psd->station_type))) {
440 if (m_last_reference_not_found.IsSameAs(
442 return TC_MASTER_HARMONICS_NOT_FOUND;
445 m_last_reference_not_found.Clear();
449 char linrec[linelen];
451 fp = fopen(m_harmfile_name.mb_str(),
"r");
452 if (fp == 0)
return TC_MASTER_HARMONICS_NOT_FOUND;
454 while (read_next_line(fp, linrec, 1)) {
462 psd->amplitude = (
double *)malloc(num_csts *
sizeof(
double));
463 psd->epoch = (
double *)malloc(num_csts *
sizeof(
double));
464 psd->station_name = (
char *)malloc(strlen(linrec) + 1);
468 strcpy(psd->station_name, linrec);
471 wxString caplin(linrec, wxConvUTF8);
473 if (caplin.Contains(
"CURRENT"))
474 psd->station_type =
'C';
476 psd->station_type =
'T';
479 read_next_line(fp, linrec, 0);
480 psd->meridian = hhmm2seconds(linrec);
481 psd->zone_offset = 0;
484 if (sscanf(nojunk(linrec),
"%s %s", junk, psd->tzfile) < 2)
485 strcpy(psd->tzfile,
"UTC0");
488 read_next_line(fp, linrec, 0);
489 if (sscanf(nojunk(linrec),
"%lf %s", &(psd->DATUM), psd->unit) < 2)
490 strcpy(psd->unit,
"unknown");
492 if ((a = findunit(psd->unit)) == -1) {
498 psd->have_BOGUS = (findunit(psd->unit) != -1) &&
499 (known_units[findunit(psd->unit)].type == BOGUS);
503 unit_c = findunit(
"knots");
505 unit_c = findunit(psd->unit);
508 strcpy(psd->units_conv, known_units[unit_c].name);
509 strcpy(psd->units_abbrv, known_units[unit_c].abbrv);
514 for (a = 0; a < num_csts; a++) {
515 read_next_line(fp, linrec, 0);
516 sscanf(linrec,
"%s %lf %lf", junk, &loca, &loce);
518 psd->amplitude[a] = loca;
519 psd->epoch[a] = loce * M_PI / 180.;
528 return TC_MASTER_HARMONICS_NOT_FOUND;
530 m_msd_array.Add(psd);
540long TCDS_Ascii_Harmonic::IndexFileIO(
int func,
long value) {
546 if (m_IndexFile) fclose(m_IndexFile);
552 m_IndexFile = fopen(m_indexfile_name.mb_str(),
"rt");
553 if (m_IndexFile == NULL)
return (0);
558 return (ftell(m_IndexFile));
562 return (fseek(m_IndexFile, value, SEEK_SET));
566 str = fgets(index_line_buffer, 1024, m_IndexFile);
577int TCDS_Ascii_Harmonic::read_next_line(FILE *fp,
char linrec[linelen],
580 if (!fgets(linrec, linelen, fp)) {
587 }
while (linrec[0] ==
'#' || linrec[0] ==
'\r' || linrec[0] ==
'\n');
592int TCDS_Ascii_Harmonic::skipnl(FILE *fp) {
593 char linrec[linelen];
594 if (NULL == fgets(linrec, linelen, fp))
return 0;
599char *TCDS_Ascii_Harmonic::nojunk(
char *line) {
601 a = &(line[strlen(line)]);
603 if (*(a - 1) ==
'\n' || *(a - 1) ==
'\r' || *(a - 1) ==
' ')
615int TCDS_Ascii_Harmonic::slackcmp(
char *a,
char *b) {
618 if ((
int)(strlen(a)) < n)
return 1;
619 for (c = 0; c < n; c++) {
620 if (b[c] ==
'?')
continue;
622 cmp = ((a[c] >=
'A' && a[c] <=
'Z') ? a[c] -
'A' +
'a' : a[c]) -
623 ((b[c] >=
'A' && b[c] <=
'Z') ? b[c] -
'A' +
'a' : b[c]);
629void TCDS_Ascii_Harmonic::free_cst() {
633void TCDS_Ascii_Harmonic::free_nodes() {
635 if (num_csts && m_cst_nodes)
636 for (a = 0; a < num_csts; a++) free(m_cst_nodes[a]);
642void TCDS_Ascii_Harmonic::free_epochs() {
644 if (num_csts && m_cst_epochs)
645 for (a = 0; a < num_csts; a++) free(m_cst_epochs[a]);
652void TCDS_Ascii_Harmonic::free_data() {
654 m_work_buffer = NULL;
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.
char IDX_zone[40]
Geographic zone identifier.
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_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.
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 IDX_ref_file_num
Reference file number.
int num_csts
Number of harmonic constituents.
char * IDX_tzname
Timezone name (dynamically allocated)
float IDX_ht_off
High tide height offset.
int IDX_sta_num
Subordinate station number (UNUSED)
@ SOURCE_TYPE_ASCII_HARMONIC
ASCII harmonic source type.
Load harmonic data from ascii source TCDataFactory.