24#include <wx/filename.h>
25#include <wx/tokenzr.h>
29#include "TCDS_Ascii_Harmonic.h"
32#define M_PI ((2) * (acos(0.0)))
48static int hhmm2seconds(
char *hhmm) {
51 if (sscanf(hhmm,
"%d:%d", &h, &m) != 2)
return (0);
52 if (sscanf(hhmm,
"%c", &s) != 1)
return (0);
53 if (h < 0 || s ==
'-') m = -m;
54 return h * 3600 + m * 60;
57TCDS_Ascii_Harmonic::TCDS_Ascii_Harmonic() {
72TCDS_Ascii_Harmonic::~TCDS_Ascii_Harmonic() {
78TC_Error_Code TCDS_Ascii_Harmonic::LoadData(
const wxString &data_file_path) {
79 if (m_IndexFile) IndexFileIO(IFF_CLOSE, 0);
81 m_indexfile_name = data_file_path;
83 TC_Error_Code error_return = init_index_file();
84 if (error_return != TC_NO_ERROR)
return error_return;
86 wxFileName f(data_file_path);
87 m_harmfile_name = f.GetPath(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME);
88 m_harmfile_name += f.GetName();
89 error_return = LoadHarmonicConstants(m_harmfile_name);
92 unsigned int max_index = GetMaxIndex();
93 for (
unsigned int i = 0; i < max_index; i++) {
110IDX_entry *TCDS_Ascii_Harmonic::GetIndexEntry(
int n_index) {
111 return &m_IDX_array[n_index];
114TC_Error_Code TCDS_Ascii_Harmonic::init_index_file() {
115 long int xref_start = 0;
119 m_abbreviation_array.clear();
123 int index_in_memory = 0;
125 if (IndexFileIO(IFF_OPEN, 0)) {
126 while (IndexFileIO(IFF_READ, 0)) {
127 if ((index_line_buffer[0] ==
'#') || (index_line_buffer[0] <=
' '))
129 else if (!have_index && !xref_start) {
130 if (!strncmp(index_line_buffer,
"XREF", 4))
131 xref_start = IndexFileIO(IFF_TELL, 0);
132 }
else if (!have_index && !strncmp(index_line_buffer,
"*END*", 5)) {
133 if (m_abbreviation_array.empty()) {
134 IndexFileIO(IFF_CLOSE, 0);
135 return (TC_INDEX_FILE_CORRUPT);
143 else if (!have_index && xref_start) {
144 wxString line(index_line_buffer, wxConvUTF8);
148 wxStringTokenizer tkz(line, _T(
" "));
149 wxString token = tkz.GetNextToken();
150 if (token.IsSameAs(_T(
"REGION"), FALSE))
152 else if (token.IsSameAs(_T(
"COUNTRY"), FALSE))
153 entry.type = COUNTRY;
154 else if (token.IsSameAs(_T(
"STATE"), FALSE))
157 token = tkz.GetNextToken();
158 entry.short_s = token;
160 entry.long_s = line.Mid(tkz.GetPosition()).Strip();
162 m_abbreviation_array.push_back(entry);
166 else if (have_index && (strchr(
"TtCcIUu", index_line_buffer[0]))) {
173 index_in_memory = TRUE;
176 if (TC_NO_ERROR != build_IDX_entry(pIDX)) {
179 m_IDX_array.Add(pIDX);
183 else if (have_index && (index_line_buffer[0] ==
'H')) {
185 sscanf(index_line,
"Harmonic %s", s1);
186 pHarmonic = harmonic_file_list;
187 while (pHarmonic && pHarmonic->next)
189 pHarmonic_prev = pHarmonic;
191 if (NULL == pHarmonic) {
193 free_harmonic_file_list();
196 if (!harmonic_file_list)
197 harmonic_file_list = pHarmonic;
198 else pHarmonic_prev->next = pHarmonic;
199 pHarmonic->next = NULL;
200 pHarmonic->rec_start = num_IDX;
201 if (allocate_copy_string(&pHarmonic->name,s1)) {
203 free_harmonic_file_list();
209 if (index_in_memory) IndexFileIO(IFF_CLOSE, 0);
214 return (TC_NO_ERROR);
221TC_Error_Code TCDS_Ascii_Harmonic::build_IDX_entry(
IDX_entry *pIDX) {
231 if (7 != sscanf(index_line_buffer,
"%c%s%lf%lf%d:%d%*c%[^\r\n]",
234 return (TC_INDEX_ENTRY_BAD);
236 if (TZHr < 0 && TZMin > 0)
242 index_line_buffer[0])) {
243 IndexFileIO(IFF_READ, 0);
245 if (index_line_buffer[0] ==
'^')
247 if (11 != sscanf(index_line_buffer,
248 "%*c%d %f %f %d %f %f %d %d %d %d%*c%[^\r\n]",
254 return (TC_INDEX_ENTRY_BAD);
269 if (9 != sscanf(index_line_buffer,
270 "%*c%d %f %f %d %f %f %d %d%*c%[^\r\n]",
277 if (10 != sscanf(index_line_buffer,
278 "%*c%d %f %f %d %f %f %d %s %d%*c%[^\r\n]",
284 return (TC_INDEX_ENTRY_BAD);
286 if (NULL != (pIDX->
IDX_tzname = (
char *)malloc(strlen(stz) + 1)))
326 return (TC_NO_ERROR);
330TC_Error_Code TCDS_Ascii_Harmonic::LoadHarmonicConstants(
331 const wxString &data_file_path) {
333 char linrec[linelen];
339 fp = fopen(data_file_path.mb_str(),
"r");
340 if (NULL == fp)
return TC_FILE_NOT_FOUND;
342 read_next_line(fp, linrec, 0);
344 if (1 != sscanf(linrec,
"%d", &num_csts))
goto error;
350 m_cst_speeds = (
double *)malloc(num_csts *
sizeof(
double));
351 m_work_buffer = (
double *)malloc(num_csts *
sizeof(
double));
354 for (a = 0; a < num_csts; a++) {
355 read_next_line(fp, linrec, 0);
356 sscanf(linrec,
"%s %lf", junk, &(m_cst_speeds[a]));
357 m_cst_speeds[a] *= M_PI / 648000;
361 read_next_line(fp, linrec, 0);
362 sscanf(linrec,
"%d", &m_first_year);
365 read_next_line(fp, linrec, 0);
366 if (1 != sscanf(linrec,
"%d", &num_epochs))
goto error;
367 if (num_epochs <= 0 || num_epochs > 1000000)
goto error;
369 m_cst_epochs = (
double **)malloc(num_csts *
sizeof(
double *));
370 for (
int i = 0; i < num_csts; i++)
371 m_cst_epochs[i] = (
double *)malloc(num_epochs *
sizeof(
double));
373 for (
int i = 0; i < num_csts; i++) {
374 if (1 != fscanf(fp,
"%s", linrec))
goto error;
375 for (
int b = 0; b < num_epochs; b++) {
376 if (1 != fscanf(fp,
"%lf", &(m_cst_epochs[i][b])))
goto error;
377 m_cst_epochs[i][b] *= M_PI / 180.0;
382 if (1 != fscanf(fp,
"%s", linrec))
goto error;
386 read_next_line(fp, linrec, 0);
387 if (1 != sscanf(linrec,
"%d", &num_nodes))
goto error;
388 if (num_nodes <= 0 || num_nodes > 1000000)
goto error;
390 m_cst_nodes = (
double **)malloc(num_csts *
sizeof(
double *));
391 for (
int a = 0; a < num_csts; a++)
392 m_cst_nodes[a] = (
double *)malloc(num_nodes *
sizeof(
double));
394 for (
int a = 0; a < num_csts; a++) {
395 int ignore = fscanf(fp,
"%s", linrec);
396 for (b = 0; b < num_nodes; b++)
397 ignore = fscanf(fp,
"%lf", &(m_cst_nodes[a][b]));
406 return TC_HARM_FILE_CORRUPT;
409TC_Error_Code TCDS_Ascii_Harmonic::LoadHarmonicData(
IDX_entry *pIDX) {
416 for (
unsigned int i = 0; i < m_msd_array.GetCount(); i++) {
417 psd = &m_msd_array[i];
427 (toupper(pIDX->
IDX_type) == psd->station_type)) {
439 if (m_last_reference_not_found.IsSameAs(
441 return TC_MASTER_HARMONICS_NOT_FOUND;
444 m_last_reference_not_found.Clear();
448 char linrec[linelen];
450 fp = fopen(m_harmfile_name.mb_str(),
"r");
451 if (fp == 0)
return TC_MASTER_HARMONICS_NOT_FOUND;
453 while (read_next_line(fp, linrec, 1)) {
461 psd->amplitude = (
double *)malloc(num_csts *
sizeof(
double));
462 psd->epoch = (
double *)malloc(num_csts *
sizeof(
double));
463 psd->station_name = (
char *)malloc(strlen(linrec) + 1);
467 strcpy(psd->station_name, linrec);
470 wxString caplin(linrec, wxConvUTF8);
472 if (caplin.Contains(_T(
"CURRENT")))
473 psd->station_type =
'C';
475 psd->station_type =
'T';
478 read_next_line(fp, linrec, 0);
479 psd->meridian = hhmm2seconds(linrec);
480 psd->zone_offset = 0;
483 if (sscanf(nojunk(linrec),
"%s %s", junk, psd->tzfile) < 2)
484 strcpy(psd->tzfile,
"UTC0");
487 read_next_line(fp, linrec, 0);
488 if (sscanf(nojunk(linrec),
"%lf %s", &(psd->DATUM), psd->unit) < 2)
489 strcpy(psd->unit,
"unknown");
491 if ((a = findunit(psd->unit)) == -1) {
497 psd->have_BOGUS = (findunit(psd->unit) != -1) &&
498 (known_units[findunit(psd->unit)].type == BOGUS);
502 unit_c = findunit(
"knots");
504 unit_c = findunit(psd->unit);
507 strcpy(psd->units_conv, known_units[unit_c].name);
508 strcpy(psd->units_abbrv, known_units[unit_c].abbrv);
513 for (a = 0; a < num_csts; a++) {
514 read_next_line(fp, linrec, 0);
515 sscanf(linrec,
"%s %lf %lf", junk, &loca, &loce);
517 psd->amplitude[a] = loca;
518 psd->epoch[a] = loce * M_PI / 180.;
527 return TC_MASTER_HARMONICS_NOT_FOUND;
529 m_msd_array.Add(psd);
539long TCDS_Ascii_Harmonic::IndexFileIO(
int func,
long value) {
545 if (m_IndexFile) fclose(m_IndexFile);
551 m_IndexFile = fopen(m_indexfile_name.mb_str(),
"rt");
552 if (m_IndexFile == NULL)
return (0);
557 return (ftell(m_IndexFile));
561 return (fseek(m_IndexFile, value, SEEK_SET));
565 str = fgets(index_line_buffer, 1024, m_IndexFile);
576int TCDS_Ascii_Harmonic::read_next_line(FILE *fp,
char linrec[linelen],
579 if (!fgets(linrec, linelen, fp)) {
586 }
while (linrec[0] ==
'#' || linrec[0] ==
'\r' || linrec[0] ==
'\n');
591int TCDS_Ascii_Harmonic::skipnl(FILE *fp) {
592 char linrec[linelen];
593 if (NULL == fgets(linrec, linelen, fp))
return 0;
598char *TCDS_Ascii_Harmonic::nojunk(
char *line) {
600 a = &(line[strlen(line)]);
602 if (*(a - 1) ==
'\n' || *(a - 1) ==
'\r' || *(a - 1) ==
' ')
614int TCDS_Ascii_Harmonic::slackcmp(
char *a,
char *b) {
617 if ((
int)(strlen(a)) < n)
return 1;
618 for (c = 0; c < n; c++) {
619 if (b[c] ==
'?')
continue;
621 cmp = ((a[c] >=
'A' && a[c] <=
'Z') ? a[c] -
'A' +
'a' : a[c]) -
622 ((b[c] >=
'A' && b[c] <=
'Z') ? b[c] -
'A' +
'a' : b[c]);
628void TCDS_Ascii_Harmonic::free_cst() {
632void TCDS_Ascii_Harmonic::free_nodes() {
634 if (num_csts && m_cst_nodes)
635 for (a = 0; a < num_csts; a++) free(m_cst_nodes[a]);
641void TCDS_Ascii_Harmonic::free_epochs() {
643 if (num_csts && m_cst_epochs)
644 for (a = 0; a < num_csts; a++) free(m_cst_epochs[a]);
651void TCDS_Ascii_Harmonic::free_data() {
653 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)