24 #include <wx/filename.h>
25 #include <wx/tokenzr.h>
29 #include "TCDS_Ascii_Harmonic.h"
32 #define M_PI ((2) * (acos(0.0)))
48 static 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;
57 TCDS_Ascii_Harmonic::TCDS_Ascii_Harmonic() {
72 TCDS_Ascii_Harmonic::~TCDS_Ascii_Harmonic() {
78 TC_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++) {
96 pIDX->num_nodes = num_nodes;
97 pIDX->num_csts = num_csts;
98 pIDX->num_epochs = num_epochs;
99 pIDX->m_cst_speeds = m_cst_speeds;
100 pIDX->m_cst_nodes = m_cst_nodes;
101 pIDX->m_cst_epochs = m_cst_epochs;
102 pIDX->first_year = m_first_year;
103 pIDX->m_work_buffer = m_work_buffer;
110 IDX_entry *TCDS_Ascii_Harmonic::GetIndexEntry(
int n_index) {
111 return &m_IDX_array[n_index];
114 TC_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]))) {
170 pIDX->source_data_type = SOURCE_TYPE_ASCII_HARMONIC;
171 pIDX->pDataSource = NULL;
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);
221 TC_Error_Code TCDS_Ascii_Harmonic::build_IDX_entry(
IDX_entry *pIDX) {
225 pIDX->pref_sta_data = NULL;
226 pIDX->IDX_Useable = 1;
228 pIDX->IDX_tzname = NULL;
231 if (7 != sscanf(index_line_buffer,
"%c%s%lf%lf%d:%d%*c%[^\r\n]",
232 &pIDX->IDX_type, &pIDX->IDX_zone[0], &pIDX->IDX_lon,
233 &pIDX->IDX_lat, &TZHr, &TZMin, &pIDX->IDX_station_name[0]))
234 return (TC_INDEX_ENTRY_BAD);
236 if (TZHr < 0 && TZMin > 0)
239 pIDX->IDX_time_zone = TZHr * 60 + TZMin;
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]",
249 &pIDX->IDX_ht_time_off, &pIDX->IDX_ht_mpy,
250 &pIDX->IDX_ht_off, &pIDX->IDX_lt_time_off,
251 &pIDX->IDX_lt_mpy, &pIDX->IDX_lt_off, &pIDX->IDX_sta_num,
252 &pIDX->IDX_flood_dir, &pIDX->IDX_ebb_dir,
253 &pIDX->IDX_ref_file_num, pIDX->IDX_reference_name))
254 return (TC_INDEX_ENTRY_BAD);
256 if (abs(pIDX->IDX_ht_time_off) > 1000)
257 pIDX->IDX_Useable = 0;
259 if (abs(pIDX->IDX_flood_dir) > 360)
260 pIDX->IDX_Useable = 0;
261 if (abs(pIDX->IDX_ebb_dir) > 360)
262 pIDX->IDX_Useable = 0;
265 if (pIDX->IDX_ht_mpy == 0.0) pIDX->IDX_ht_mpy = 1.0;
266 if (pIDX->IDX_lt_mpy == 0.0) pIDX->IDX_lt_mpy = 1.0;
269 if (9 != sscanf(index_line_buffer,
270 "%*c%d %f %f %d %f %f %d %d%*c%[^\r\n]",
271 &pIDX->IDX_ht_time_off, &pIDX->IDX_ht_mpy,
272 &pIDX->IDX_ht_off, &pIDX->IDX_lt_time_off,
273 &pIDX->IDX_lt_mpy, &pIDX->IDX_lt_off, &pIDX->IDX_sta_num,
274 &pIDX->IDX_ref_file_num, pIDX->IDX_reference_name)) {
277 if (10 != sscanf(index_line_buffer,
278 "%*c%d %f %f %d %f %f %d %s %d%*c%[^\r\n]",
279 &pIDX->IDX_ht_time_off, &pIDX->IDX_ht_mpy,
280 &pIDX->IDX_ht_off, &pIDX->IDX_lt_time_off,
281 &pIDX->IDX_lt_mpy, &pIDX->IDX_lt_off,
282 &pIDX->IDX_sta_num, stz, &pIDX->IDX_ref_file_num,
283 pIDX->IDX_reference_name))
284 return (TC_INDEX_ENTRY_BAD);
286 if (NULL != (pIDX->IDX_tzname = (
char *)malloc(strlen(stz) + 1)))
287 strcpy(pIDX->IDX_tzname, stz);
293 pIDX->IDX_ref_file_num = 0;
311 pIDX->IDX_ht_time_off = pIDX->IDX_lt_time_off = 0;
312 pIDX->IDX_ht_mpy = pIDX->IDX_lt_mpy = 1.0;
313 pIDX->IDX_ht_off = pIDX->IDX_lt_off = 0.0;
314 pIDX->IDX_sta_num = 0;
315 strcpy(pIDX->IDX_reference_name, pIDX->IDX_station_name);
318 if (pIDX->IDX_ht_time_off || pIDX->IDX_ht_off != 0.0 ||
319 pIDX->IDX_lt_off != 0.0 || pIDX->IDX_ht_mpy != 1.0 ||
320 pIDX->IDX_lt_mpy != 1.0)
321 pIDX->have_offsets = 1;
323 pIDX->station_tz_offset =
326 return (TC_NO_ERROR);
330 TC_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;
409 TC_Error_Code TCDS_Ascii_Harmonic::LoadHarmonicData(
IDX_entry *pIDX) {
413 if (pIDX->pref_sta_data)
return TC_NO_ERROR;
416 for (
unsigned int i = 0; i < m_msd_array.GetCount(); i++) {
417 psd = &m_msd_array[i];
426 if ((!slackcmp(psd->station_name, pIDX->IDX_reference_name)) &&
427 (toupper(pIDX->IDX_type) == psd->station_type)) {
428 pIDX->pref_sta_data = psd;
439 if (m_last_reference_not_found.IsSameAs(
440 wxString(pIDX->IDX_reference_name, wxConvUTF8)))
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)) {
455 if (slackcmp(linrec, pIDX->IDX_reference_name))
continue;
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.;
526 m_last_reference_not_found = wxString(pIDX->IDX_reference_name, wxConvUTF8);
527 return TC_MASTER_HARMONICS_NOT_FOUND;
529 m_msd_array.Add(psd);
530 pIDX->pref_sta_data = psd;
539 long 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);
576 int 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');
591 int TCDS_Ascii_Harmonic::skipnl(FILE *fp) {
592 char linrec[linelen];
593 if (NULL == fgets(linrec, linelen, fp))
return 0;
598 char *TCDS_Ascii_Harmonic::nojunk(
char *line) {
600 a = &(line[strlen(line)]);
602 if (*(a - 1) ==
'\n' || *(a - 1) ==
'\r' || *(a - 1) ==
' ')
614 int 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]);
628 void TCDS_Ascii_Harmonic::free_cst() {
632 void 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]);
641 void 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]);
651 void TCDS_Ascii_Harmonic::free_data() {
653 m_work_buffer = NULL;