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() {
71TCDS_Ascii_Harmonic::~TCDS_Ascii_Harmonic() {
77TC_Error_Code TCDS_Ascii_Harmonic::LoadData(
const wxString &data_file_path) {
78 if (m_IndexFile) IndexFileIO(IFF_CLOSE, 0);
80 m_indexfile_name = data_file_path;
82 TC_Error_Code error_return = init_index_file();
83 if (error_return != TC_NO_ERROR)
return error_return;
85 wxFileName f(data_file_path);
86 m_harmfile_name = f.GetPath(wxPATH_GET_SEPARATOR | wxPATH_GET_VOLUME);
87 m_harmfile_name += f.GetName();
88 error_return = LoadHarmonicConstants(m_harmfile_name);
91 unsigned int max_index = GetMaxIndex();
92 for (
unsigned int i = 0; i < max_index; i++) {
95 pIDX->num_nodes = num_nodes;
96 pIDX->num_csts = num_csts;
97 pIDX->num_epochs = num_epochs;
98 pIDX->m_cst_speeds = m_cst_speeds;
99 pIDX->m_cst_nodes = m_cst_nodes;
100 pIDX->m_cst_epochs = m_cst_epochs;
101 pIDX->first_year = m_first_year;
102 pIDX->m_work_buffer = m_work_buffer;
109IDX_entry *TCDS_Ascii_Harmonic::GetIndexEntry(
int n_index) {
110 return &m_IDX_array[n_index];
113TC_Error_Code TCDS_Ascii_Harmonic::init_index_file() {
114 long int xref_start = 0;
118 m_abbreviation_array.clear();
122 int index_in_memory = 0;
124 if (IndexFileIO(IFF_OPEN, 0)) {
125 while (IndexFileIO(IFF_READ, 0)) {
126 if ((index_line_buffer[0] ==
'#') || (index_line_buffer[0] <=
' '))
128 else if (!have_index && !xref_start) {
129 if (!strncmp(index_line_buffer,
"XREF", 4))
130 xref_start = IndexFileIO(IFF_TELL, 0);
131 }
else if (!have_index && !strncmp(index_line_buffer,
"*END*", 5)) {
132 if (m_abbreviation_array.empty()) {
133 IndexFileIO(IFF_CLOSE, 0);
134 return (TC_INDEX_FILE_CORRUPT);
142 else if (!have_index && xref_start) {
143 wxString line(index_line_buffer, wxConvUTF8);
147 wxStringTokenizer tkz(line, _T(
" "));
148 wxString token = tkz.GetNextToken();
149 if (token.IsSameAs(_T(
"REGION"), FALSE))
151 else if (token.IsSameAs(_T(
"COUNTRY"), FALSE))
152 entry.type = COUNTRY;
153 else if (token.IsSameAs(_T(
"STATE"), FALSE))
156 token = tkz.GetNextToken();
157 entry.short_s = token;
159 entry.long_s = line.Mid(tkz.GetPosition()).Strip();
161 m_abbreviation_array.push_back(entry);
165 else if (have_index && (strchr(
"TtCcIUu", index_line_buffer[0]))) {
169 pIDX->source_data_type = SOURCE_TYPE_ASCII_HARMONIC;
170 pIDX->pDataSource = NULL;
172 index_in_memory = TRUE;
175 if (TC_NO_ERROR != build_IDX_entry(pIDX)) {
178 m_IDX_array.Add(pIDX);
182 else if (have_index && (index_line_buffer[0] ==
'H')) {
184 sscanf(index_line,
"Harmonic %s", s1);
185 pHarmonic = harmonic_file_list;
186 while (pHarmonic && pHarmonic->next)
188 pHarmonic_prev = pHarmonic;
190 if (NULL == pHarmonic) {
192 free_harmonic_file_list();
195 if (!harmonic_file_list)
196 harmonic_file_list = pHarmonic;
197 else pHarmonic_prev->next = pHarmonic;
198 pHarmonic->next = NULL;
199 pHarmonic->rec_start = num_IDX;
200 if (allocate_copy_string(&pHarmonic->name,s1)) {
202 free_harmonic_file_list();
208 if (index_in_memory) IndexFileIO(IFF_CLOSE, 0);
213 return (TC_NO_ERROR);
220TC_Error_Code TCDS_Ascii_Harmonic::build_IDX_entry(
IDX_entry *pIDX) {
224 pIDX->pref_sta_data = NULL;
225 pIDX->IDX_Useable = 1;
227 pIDX->IDX_tzname = NULL;
230 if (7 != sscanf(index_line_buffer,
"%c%s%lf%lf%d:%d%*c%[^\r\n]",
231 &pIDX->IDX_type, &pIDX->IDX_zone[0], &pIDX->IDX_lon,
232 &pIDX->IDX_lat, &TZHr, &TZMin, &pIDX->IDX_station_name[0]))
233 return (TC_INDEX_ENTRY_BAD);
235 if (TZHr < 0 && TZMin > 0)
238 pIDX->IDX_time_zone = TZHr * 60 + TZMin;
241 index_line_buffer[0])) {
242 IndexFileIO(IFF_READ, 0);
244 if (index_line_buffer[0] ==
'^')
246 if (11 != sscanf(index_line_buffer,
247 "%*c%d %f %f %d %f %f %d %d %d %d%*c%[^\r\n]",
248 &pIDX->IDX_ht_time_off, &pIDX->IDX_ht_mpy,
249 &pIDX->IDX_ht_off, &pIDX->IDX_lt_time_off,
250 &pIDX->IDX_lt_mpy, &pIDX->IDX_lt_off, &pIDX->IDX_sta_num,
251 &pIDX->IDX_flood_dir, &pIDX->IDX_ebb_dir,
252 &pIDX->IDX_ref_file_num, pIDX->IDX_reference_name))
253 return (TC_INDEX_ENTRY_BAD);
255 if (abs(pIDX->IDX_ht_time_off) > 1000)
256 pIDX->IDX_Useable = 0;
258 if (abs(pIDX->IDX_flood_dir) > 360)
259 pIDX->IDX_Useable = 0;
260 if (abs(pIDX->IDX_ebb_dir) > 360)
261 pIDX->IDX_Useable = 0;
264 if (pIDX->IDX_ht_mpy == 0.0) pIDX->IDX_ht_mpy = 1.0;
265 if (pIDX->IDX_lt_mpy == 0.0) pIDX->IDX_lt_mpy = 1.0;
268 if (9 != sscanf(index_line_buffer,
269 "%*c%d %f %f %d %f %f %d %d%*c%[^\r\n]",
270 &pIDX->IDX_ht_time_off, &pIDX->IDX_ht_mpy,
271 &pIDX->IDX_ht_off, &pIDX->IDX_lt_time_off,
272 &pIDX->IDX_lt_mpy, &pIDX->IDX_lt_off, &pIDX->IDX_sta_num,
273 &pIDX->IDX_ref_file_num, pIDX->IDX_reference_name)) {
276 if (10 != sscanf(index_line_buffer,
277 "%*c%d %f %f %d %f %f %d %s %d%*c%[^\r\n]",
278 &pIDX->IDX_ht_time_off, &pIDX->IDX_ht_mpy,
279 &pIDX->IDX_ht_off, &pIDX->IDX_lt_time_off,
280 &pIDX->IDX_lt_mpy, &pIDX->IDX_lt_off,
281 &pIDX->IDX_sta_num, stz, &pIDX->IDX_ref_file_num,
282 pIDX->IDX_reference_name))
283 return (TC_INDEX_ENTRY_BAD);
285 if (NULL != (pIDX->IDX_tzname = (
char *)malloc(strlen(stz) + 1)))
286 strcpy(pIDX->IDX_tzname, stz);
292 pIDX->IDX_ref_file_num = 0;
310 pIDX->IDX_ht_time_off = pIDX->IDX_lt_time_off = 0;
311 pIDX->IDX_ht_mpy = pIDX->IDX_lt_mpy = 1.0;
312 pIDX->IDX_ht_off = pIDX->IDX_lt_off = 0.0;
313 pIDX->IDX_sta_num = 0;
314 strcpy(pIDX->IDX_reference_name, pIDX->IDX_station_name);
317 if (pIDX->IDX_ht_time_off || pIDX->IDX_ht_off != 0.0 ||
318 pIDX->IDX_lt_off != 0.0 || pIDX->IDX_ht_mpy != 1.0 ||
319 pIDX->IDX_lt_mpy != 1.0)
320 pIDX->have_offsets = 1;
322 pIDX->station_tz_offset =
325 return (TC_NO_ERROR);
329TC_Error_Code TCDS_Ascii_Harmonic::LoadHarmonicConstants(
330 const wxString &data_file_path) {
332 char linrec[linelen];
338 fp = fopen(data_file_path.mb_str(),
"r");
339 if (NULL == fp)
return TC_FILE_NOT_FOUND;
341 read_next_line(fp, linrec, 0);
343 if (1 != sscanf(linrec,
"%d", &num_csts))
goto error;
349 m_cst_speeds = (
double *)malloc(num_csts *
sizeof(
double));
350 m_work_buffer = (
double *)malloc(num_csts *
sizeof(
double));
353 for (a = 0; a < num_csts; a++) {
354 read_next_line(fp, linrec, 0);
355 sscanf(linrec,
"%s %lf", junk, &(m_cst_speeds[a]));
356 m_cst_speeds[a] *= M_PI / 648000;
360 read_next_line(fp, linrec, 0);
361 sscanf(linrec,
"%d", &m_first_year);
364 read_next_line(fp, linrec, 0);
365 if (1 != sscanf(linrec,
"%d", &num_epochs))
goto error;
366 if (num_epochs <= 0 || num_epochs > 1000000)
goto error;
368 m_cst_epochs = (
double **)malloc(num_csts *
sizeof(
double *));
369 for (
int i = 0; i < num_csts; i++)
370 m_cst_epochs[i] = (
double *)malloc(num_epochs *
sizeof(
double));
372 for (
int i = 0; i < num_csts; i++) {
373 if (1 != fscanf(fp,
"%s", linrec))
goto error;
374 for (
int b = 0; b < num_epochs; b++) {
375 if (1 != fscanf(fp,
"%lf", &(m_cst_epochs[i][b])))
goto error;
376 m_cst_epochs[i][b] *= M_PI / 180.0;
381 if (1 != fscanf(fp,
"%s", linrec))
goto error;
385 read_next_line(fp, linrec, 0);
386 if (1 != sscanf(linrec,
"%d", &num_nodes))
goto error;
387 if (num_nodes <= 0 || num_nodes > 1000000)
goto error;
389 m_cst_nodes = (
double **)malloc(num_csts *
sizeof(
double *));
390 for (
int a = 0; a < num_csts; a++)
391 m_cst_nodes[a] = (
double *)malloc(num_nodes *
sizeof(
double));
393 for (
int a = 0; a < num_csts; a++) {
394 int ignore = fscanf(fp,
"%s", linrec);
395 for (b = 0; b < num_nodes; b++)
396 ignore = fscanf(fp,
"%lf", &(m_cst_nodes[a][b]));
405 return TC_HARM_FILE_CORRUPT;
408TC_Error_Code TCDS_Ascii_Harmonic::LoadHarmonicData(
IDX_entry *pIDX) {
412 if (pIDX->pref_sta_data)
return TC_NO_ERROR;
415 for (
unsigned int i = 0; i < m_msd_array.GetCount(); i++) {
416 psd = &m_msd_array[i];
425 if ((!slackcmp(psd->station_name, pIDX->IDX_reference_name)) &&
426 (toupper(pIDX->IDX_type) == psd->station_type)) {
427 pIDX->pref_sta_data = psd;
438 if (m_last_reference_not_found.IsSameAs(
439 wxString(pIDX->IDX_reference_name, wxConvUTF8)))
440 return TC_MASTER_HARMONICS_NOT_FOUND;
443 m_last_reference_not_found.Clear();
447 char linrec[linelen];
449 fp = fopen(m_harmfile_name.mb_str(),
"r");
450 if (fp == 0)
return TC_MASTER_HARMONICS_NOT_FOUND;
452 while (read_next_line(fp, linrec, 1)) {
456 if (!strstr(linrec,
"Current"))
continue;
461 if (slackcmp(linrec, pIDX->IDX_reference_name))
continue;
467 psd->amplitude = (
double *)malloc(num_csts *
sizeof(
double));
468 psd->epoch = (
double *)malloc(num_csts *
sizeof(
double));
469 psd->station_name = (
char *)malloc(strlen(linrec) + 1);
473 strcpy(psd->station_name, linrec);
476 wxString caplin(linrec, wxConvUTF8);
478 if (caplin.Contains(_T(
"CURRENT")))
479 psd->station_type =
'C';
481 psd->station_type =
'T';
484 read_next_line(fp, linrec, 0);
485 psd->meridian = hhmm2seconds(linrec);
486 psd->zone_offset = 0;
489 if (sscanf(nojunk(linrec),
"%s %s", junk, psd->tzfile) < 2)
490 strcpy(psd->tzfile,
"UTC0");
493 read_next_line(fp, linrec, 0);
494 if (sscanf(nojunk(linrec),
"%lf %s", &(psd->DATUM), psd->unit) < 2)
495 strcpy(psd->unit,
"unknown");
497 if ((a = findunit(psd->unit)) == -1) {
503 psd->have_BOGUS = (findunit(psd->unit) != -1) &&
504 (known_units[findunit(psd->unit)].type == BOGUS);
508 unit_c = findunit(
"knots");
510 unit_c = findunit(psd->unit);
513 strcpy(psd->units_conv, known_units[unit_c].name);
514 strcpy(psd->units_abbrv, known_units[unit_c].abbrv);
519 for (a = 0; a < num_csts; a++) {
520 read_next_line(fp, linrec, 0);
521 sscanf(linrec,
"%s %lf %lf", junk, &loca, &loce);
523 psd->amplitude[a] = loca;
524 psd->epoch[a] = loce * M_PI / 180.;
532 m_last_reference_not_found = wxString(pIDX->IDX_reference_name, wxConvUTF8);
533 return TC_MASTER_HARMONICS_NOT_FOUND;
535 m_msd_array.Add(psd);
536 pIDX->pref_sta_data = psd;
545long TCDS_Ascii_Harmonic::IndexFileIO(
int func,
long value) {
551 if (m_IndexFile) fclose(m_IndexFile);
557 m_IndexFile = fopen(m_indexfile_name.mb_str(),
"rt");
558 if (m_IndexFile == NULL)
return (0);
563 return (ftell(m_IndexFile));
567 return (fseek(m_IndexFile, value, SEEK_SET));
571 str = fgets(index_line_buffer, 1024, m_IndexFile);
582int TCDS_Ascii_Harmonic::read_next_line(FILE *fp,
char linrec[linelen],
585 if (!fgets(linrec, linelen, fp)) {
592 }
while (linrec[0] ==
'#' || linrec[0] ==
'\r' || linrec[0] ==
'\n');
597int TCDS_Ascii_Harmonic::skipnl(FILE *fp) {
598 char linrec[linelen];
599 if (NULL == fgets(linrec, linelen, fp))
return 0;
604char *TCDS_Ascii_Harmonic::nojunk(
char *line) {
606 a = &(line[strlen(line)]);
608 if (*(a - 1) ==
'\n' || *(a - 1) ==
'\r' || *(a - 1) ==
' ')
620int TCDS_Ascii_Harmonic::slackcmp(
char *a,
char *b) {
623 if ((
int)(strlen(a)) < n)
return 1;
624 for (c = 0; c < n; c++) {
625 if (b[c] ==
'?')
continue;
627 cmp = ((a[c] >=
'A' && a[c] <=
'Z') ? a[c] -
'A' +
'a' : a[c]) -
628 ((b[c] >=
'A' && b[c] <=
'Z') ? b[c] -
'A' +
'a' : b[c]);
634void TCDS_Ascii_Harmonic::free_cst() {
638void TCDS_Ascii_Harmonic::free_nodes() {
640 if (num_csts && m_cst_nodes)
641 for (a = 0; a < num_csts; a++) free(m_cst_nodes[a]);
647void TCDS_Ascii_Harmonic::free_epochs() {
649 if (num_csts && m_cst_epochs)
650 for (a = 0; a < num_csts; a++) free(m_cst_epochs[a]);
657void TCDS_Ascii_Harmonic::free_data() {