2 * Reads in survey files, dealing with special characters, keywords & data
3 * Copyright (C) 1991-2003,2005,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 Olly Betts
4 * Copyright (C) 2004 Simeon Warner
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
43 #define EPSILON (REAL_EPSILON * 1000)
45 #define var(I) (pcs->Var[(I)])
47 /* true if x is not-a-number value in Compass (999.0 or -999.0) */
48 /* Compass uses 999.0 but understands Karst data which used -999.0 */
49 #define is_compass_NaN(x) ( fabs(fabs(x)-999.0) < EPSILON )
54 CTYPE_OMIT
, CTYPE_READING
, CTYPE_PLUMB
, CTYPE_INFERPLUMB
, CTYPE_HORIZ
57 /* Don't explicitly initialise as we can't set the jmp_buf - this has
58 * static scope so will be initialised like this anyway */
59 parse file
/* = { NULL, NULL, 0, fFalse, NULL } */ ;
63 static real value
[Fr
- 1];
64 #define VAL(N) value[(N)-1]
65 static real variance
[Fr
- 1];
66 #define VAR(N) variance[(N)-1]
67 static long location
[Fr
- 1];
68 #define LOC(N) location[(N)-1]
69 static int location_width
[Fr
- 1];
70 #define WID(N) location_width[(N)-1]
73 static void data_normal(void);
74 static void data_cartesian(void);
75 static void data_passage(void);
76 static void data_nosurvey(void);
77 static void data_ignore(void);
83 fp
->offset
= ftell(file
.fh
);
85 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
89 set_pos(const filepos
*fp
)
92 if (fseek(file
.fh
, fp
->offset
, SEEK_SET
) == -1)
93 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
97 report_parent(parse
* p
) {
99 report_parent(p
->parent
);
100 /* Force re-report of include tree for further errors in
102 p
->reported_where
= fFalse
;
103 /* TRANSLATORS: %s is replaced by the filename of the parent file, and %u
104 * by the line number in that file. Your translation should also contain
105 * %s:%u so that automatic parsing of error messages to determine the file
106 * and line number still works. */
107 fprintf(STDERR
, msg(/*In file included from %s:%u:\n*/5), p
->filename
, p
->line
);
111 error_list_parent_files(void)
113 if (!file
.reported_where
&& file
.parent
) {
114 report_parent(file
.parent
);
115 /* Suppress reporting of full include tree for further errors
117 file
.reported_where
= fTrue
;
122 show_line(int col
, int width
)
124 /* Rewind to beginning of line. */
125 long cur_pos
= ftell(file
.fh
);
127 if (cur_pos
< 0 || fseek(file
.fh
, file
.lpos
, SEEK_SET
) == -1)
128 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
130 /* Read the whole line and write it out. */
133 int c
= GETC(file
.fh
);
134 /* Note: isEol() is true for EOF */
136 if (c
== '\t') ++tabs
;
141 /* If we have a location in the line for the error, indicate it. */
145 while (--col
) PUTC(' ', STDERR
);
147 /* Copy tabs from line, replacing other characters with spaces - this
148 * means that the caret should line up correctly. */
149 if (fseek(file
.fh
, file
.lpos
, SEEK_SET
) == -1)
150 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
152 int c
= GETC(file
.fh
);
153 if (c
!= '\t') c
= ' ';
165 /* Revert to where we were. */
166 if (fseek(file
.fh
, cur_pos
, SEEK_SET
) == -1)
167 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
170 static int caret_width
= 0;
173 compile_v_report_fpos(int severity
, long fpos
, int en
, va_list ap
)
176 error_list_parent_files();
177 if (fpos
>= file
.lpos
)
178 col
= fpos
- file
.lpos
- caret_width
;
179 v_report(severity
, file
.filename
, file
.line
, col
, en
, ap
);
180 if (file
.fh
) show_line(col
, caret_width
);
184 compile_v_report(int diag_flags
, int en
, va_list ap
)
186 int severity
= (diag_flags
& DIAG_SEVERITY_MASK
);
187 if (diag_flags
& (DIAG_COL
|DIAG_BUF
)) {
189 if (diag_flags
& DIAG_BUF
) caret_width
= strlen(buffer
);
190 compile_v_report_fpos(severity
, ftell(file
.fh
), en
, ap
);
191 if (diag_flags
& DIAG_BUF
) caret_width
= 0;
192 if (diag_flags
& DIAG_SKIP
) skipline();
196 error_list_parent_files();
197 v_report(severity
, file
.filename
, file
.line
, 0, en
, ap
);
199 if (diag_flags
& DIAG_BUF
) {
200 show_line(0, strlen(buffer
));
202 show_line(0, caret_width
);
205 if (diag_flags
& DIAG_SKIP
) skipline();
209 compile_diagnostic(int diag_flags
, int en
, ...)
213 if (diag_flags
& (DIAG_TOKEN
|DIAG_UINT
|DIAG_DATE
|DIAG_NUM
)) {
217 if (diag_flags
& DIAG_TOKEN
) {
218 while (!isBlank(ch
) && !isEol(ch
)) {
219 s_catchar(&p
, &len
, (char)ch
);
222 } else if (diag_flags
& DIAG_UINT
) {
223 while (isdigit(ch
)) {
224 s_catchar(&p
, &len
, (char)ch
);
227 } else if (diag_flags
& DIAG_DATE
) {
228 while (isdigit(ch
) || ch
== '.') {
229 s_catchar(&p
, &len
, (char)ch
);
233 if (isMinus(ch
) || isPlus(ch
)) {
234 s_catchar(&p
, &len
, (char)ch
);
237 while (isdigit(ch
)) {
238 s_catchar(&p
, &len
, (char)ch
);
242 s_catchar(&p
, &len
, (char)ch
);
245 while (isdigit(ch
)) {
246 s_catchar(&p
, &len
, (char)ch
);
251 caret_width
= strlen(p
);
254 compile_v_report(diag_flags
|DIAG_COL
, en
, ap
);
257 compile_v_report(diag_flags
, en
, ap
);
263 compile_diagnostic_reading(int diag_flags
, reading r
, int en
, ...)
266 int severity
= (diag_flags
& DIAG_SEVERITY_MASK
);
268 caret_width
= WID(r
);
269 compile_v_report_fpos(severity
, LOC(r
) + caret_width
, en
, ap
);
275 compile_error_reading_skip(reading r
, int en
, ...)
279 caret_width
= WID(r
);
280 compile_v_report_fpos(1, LOC(r
) + caret_width
, en
, ap
);
287 compile_diagnostic_at(int diag_flags
, const char * filename
, unsigned line
, int en
, ...)
290 int severity
= (diag_flags
& DIAG_SEVERITY_MASK
);
292 v_report(severity
, filename
, line
, 0, en
, ap
);
297 compile_diagnostic_pfx(int diag_flags
, const prefix
* pfx
, int en
, ...)
300 int severity
= (diag_flags
& DIAG_SEVERITY_MASK
);
302 v_report(severity
, pfx
->filename
, pfx
->line
, 0, en
, ap
);
307 compile_diagnostic_token_show(int diag_flags
, int en
)
312 while (!isBlank(ch
) && !isEol(ch
)) {
313 s_catchar(&p
, &len
, (char)ch
);
317 caret_width
= strlen(p
);
318 compile_diagnostic(diag_flags
|DIAG_COL
, en
, p
);
322 compile_diagnostic(DIAG_ERR
|DIAG_COL
, en
, "");
327 compile_error_string(const char * s
, int en
, ...)
331 caret_width
= strlen(s
);
332 compile_v_report(DIAG_ERR
|DIAG_COL
, en
, ap
);
337 /* This function makes a note where to put output files */
339 using_data_file(const char *fnm
)
341 if (!fnm_output_base
) {
342 /* was: fnm_output_base = base_from_fnm(fnm); */
343 fnm_output_base
= baseleaf_from_fnm(fnm
);
344 } else if (fnm_output_base_is_dir
) {
345 /* --output pointed to directory so use the leaf basename in that dir */
347 lf
= baseleaf_from_fnm(fnm
);
348 p
= use_path(fnm_output_base
, lf
);
350 osfree(fnm_output_base
);
352 fnm_output_base_is_dir
= 0;
359 while (!isBlank(ch
) && !isEol(ch
)) nextch();
365 while (isBlank(ch
)) nextch();
371 while (!isEol(ch
)) nextch();
383 compile_diagnostic(DIAG_ERR
|DIAG_COL
, /*End of line not blank*/15);
389 /* skip any different eol characters so we get line counts correct on
390 * DOS text files and similar, but don't count several adjacent blank
394 if (ch
== eolchar
|| !isEol(ch
)) {
397 if (ch
== '\n') eolchar
= ch
;
399 file
.lpos
= ftell(file
.fh
) - 1;
403 process_non_data_line(void)
407 if (isData(ch
)) return fFalse
;
420 read_reading(reading r
, bool f_optional
)
425 case Tape
: q
= Q_LENGTH
; break;
426 case BackTape
: q
= Q_BACKLENGTH
; break;
427 case Comp
: q
= Q_BEARING
; break;
428 case BackComp
: q
= Q_BACKBEARING
; break;
429 case Clino
: q
= Q_GRADIENT
; break;
430 case BackClino
: q
= Q_BACKGRADIENT
; break;
431 case FrDepth
: case ToDepth
: q
= Q_DEPTH
; break;
432 case Dx
: q
= Q_DX
; break;
433 case Dy
: q
= Q_DY
; break;
434 case Dz
: q
= Q_DZ
; break;
435 case FrCount
: case ToCount
: q
= Q_COUNT
; break;
436 case Left
: q
= Q_LEFT
; break;
437 case Right
: q
= Q_RIGHT
; break;
438 case Up
: q
= Q_UP
; break;
439 case Down
: q
= Q_DOWN
; break;
441 q
= Q_NULL
; /* Suppress compiler warning */;
442 BUG("Unexpected case");
444 LOC(r
) = ftell(file
.fh
);
445 VAL(r
) = read_numeric_multi(f_optional
, &n_readings
);
446 WID(r
) = ftell(file
.fh
) - LOC(r
);
448 if (n_readings
> 1) VAR(r
) /= sqrt(n_readings
);
452 read_bearing_or_omit(reading r
)
455 q_quantity q
= Q_NULL
;
456 LOC(r
) = ftell(file
.fh
);
457 VAL(r
) = read_numeric_multi_or_omit(&n_readings
);
458 WID(r
) = ftell(file
.fh
) - LOC(r
);
460 case Comp
: q
= Q_BEARING
; break;
461 case BackComp
: q
= Q_BACKBEARING
; break;
463 q
= Q_NULL
; /* Suppress compiler warning */;
464 BUG("Unexpected case");
467 if (n_readings
> 1) VAR(r
) /= sqrt(n_readings
);
470 /* For reading Compass MAK files which have a freeform syntax */
472 nextch_handling_eol(void)
475 while (ch
!= EOF
&& isEol(ch
)) {
480 #define LITLEN(S) (sizeof(S"") - 1)
481 #define has_ext(F,L,E) ((L) > LITLEN(E) + 1 &&\
482 (F)[(L) - LITLEN(E) - 1] == FNM_SEP_EXT &&\
483 strcasecmp((F) + (L) - LITLEN(E), E) == 0)
485 data_file(const char *pth
, const char *fnm
)
487 int begin_lineno_store
;
489 volatile enum {FMT_SVX
, FMT_DAT
, FMT_MAK
} fmt
= FMT_SVX
;
497 /* file specified on command line - don't do special translation */
498 fh
= fopenWithPthAndExt(pth
, fnm
, EXT_SVX_DATA
, "rb", &filename
);
500 fh
= fopen_portable(pth
, fnm
, EXT_SVX_DATA
, "rb", &filename
);
504 compile_error_string(fnm
, /*Couldnāt open file ā%sā*/24, fnm
);
508 len
= strlen(filename
);
509 if (has_ext(filename
, len
, "dat")) {
511 } else if (has_ext(filename
, len
, "mak")) {
516 if (file
.fh
) file
.parent
= &file_store
;
518 file
.filename
= filename
;
521 file
.reported_where
= fFalse
;
523 if (fmt
== FMT_SVX
&& ch
== 0xef) {
524 /* Maybe a UTF-8 "BOM" - skip if so. */
525 if (nextch() == 0xbb && nextch() == 0xbf) {
535 using_data_file(file
.filename
);
537 begin_lineno_store
= pcs
->begin_lineno
;
538 pcs
->begin_lineno
= 0;
540 if (fmt
== FMT_DAT
) {
545 pcsNew
= osnew(settings
);
546 *pcsNew
= *pcs
; /* copy contents */
547 pcsNew
->begin_lineno
= 0;
553 pcs
->style
= STYLE_NORMAL
;
554 pcs
->units
[Q_LENGTH
] = METRES_PER_FOOT
;
555 t
= ((short*)osmalloc(ossizeof(short) * 257)) + 1;
557 t
[EOF
] = SPECIAL_EOL
;
558 memset(t
, 0, sizeof(short) * 33);
559 for (i
= 33; i
< 127; i
++) t
[i
] = SPECIAL_NAMES
;
561 for (i
= 128; i
< 256; i
++) t
[i
] = SPECIAL_NAMES
;
562 t
['\t'] |= SPECIAL_BLANK
;
563 t
[' '] |= SPECIAL_BLANK
;
564 t
['\032'] |= SPECIAL_EOL
; /* Ctrl-Z, so olde DOS text files are handled ok */
565 t
['\n'] |= SPECIAL_EOL
;
566 t
['\r'] |= SPECIAL_EOL
;
567 t
['.'] |= SPECIAL_DECIMAL
;
568 t
['-'] |= SPECIAL_MINUS
;
569 t
['+'] |= SPECIAL_PLUS
;
572 pcs
->Truncate
= INT_MAX
;
573 pcs
->infer
= BIT(INFER_EQUATES
)|BIT(INFER_EXPORTS
)|BIT(INFER_PLUMBS
);
574 } else if (fmt
== FMT_MAK
) {
579 pcsNew
= osnew(settings
);
580 *pcsNew
= *pcs
; /* copy contents */
581 pcsNew
->begin_lineno
= 0;
585 t
= ((short*)osmalloc(ossizeof(short) * 257)) + 1;
587 t
[EOF
] = SPECIAL_EOL
;
588 memset(t
, 0, sizeof(short) * 33);
589 for (i
= 33; i
< 127; i
++) t
[i
] = SPECIAL_NAMES
;
591 for (i
= 128; i
< 256; i
++) t
[i
] = SPECIAL_NAMES
;
592 t
['['] = t
[','] = t
[';'] = 0;
593 t
['\t'] |= SPECIAL_BLANK
;
594 t
[' '] |= SPECIAL_BLANK
;
595 t
['\032'] |= SPECIAL_EOL
; /* Ctrl-Z, so olde DOS text files are handled ok */
596 t
['\n'] |= SPECIAL_EOL
;
597 t
['\r'] |= SPECIAL_EOL
;
598 t
['.'] |= SPECIAL_DECIMAL
;
599 t
['-'] |= SPECIAL_MINUS
;
600 t
['+'] |= SPECIAL_PLUS
;
603 pcs
->Truncate
= INT_MAX
;
607 /* errors in nested functions can longjmp here */
608 if (setjmp(file
.jbSkipLine
)) {
614 if (fmt
== FMT_DAT
) {
615 while (ch
!= EOF
&& !ferror(file
.fh
)) {
616 static const reading compass_order
[] = {
617 Fr
, To
, Tape
, CompassDATComp
, CompassDATClino
,
618 CompassDATLeft
, CompassDATRight
, CompassDATUp
, CompassDATDown
,
619 CompassDATFlags
, IgnoreAll
621 static const reading compass_order_backsights
[] = {
622 Fr
, To
, Tape
, CompassDATComp
, CompassDATClino
,
623 CompassDATLeft
, CompassDATRight
, CompassDATUp
, CompassDATDown
,
624 CompassDATBackComp
, CompassDATBackClino
,
625 CompassDATFlags
, IgnoreAll
630 /* SURVEY NAME: <Short name> */
633 /* if (ch != ':') ... */
638 /* SURVEY DATE: 7 10 79 COMMENT:<Long name> */
641 copy_on_write_meta(pcs
);
643 int year
, month
, day
;
647 /* NB order is *month* *day* year */
651 /* Note: Larry says a 2 digit year is always 19XX */
652 if (year
< 100) year
+= 1900;
654 pcs
->meta
->days1
= pcs
->meta
->days2
= days_since_1900(year
, month
, day
);
656 pcs
->meta
->days1
= pcs
->meta
->days2
= -1;
658 pcs
->declination
= HUGE_REAL
;
669 /* DECLINATION: 1.00 FORMAT: DDDDLUDRADLN CORRECTIONS: 2.00 3.00 4.00 */
673 pcs
->z
[Q_DECLINATION
] = -read_numeric(fFalse
);
674 pcs
->z
[Q_DECLINATION
] *= pcs
->units
[Q_DECLINATION
];
676 pcs
->ordering
= compass_order
;
677 if (strcmp(buffer
, "FORMAT") == 0) {
680 if (strlen(buffer
) >= 12 && buffer
[11] == 'B') {
681 /* We have backsights for compass and clino */
682 pcs
->ordering
= compass_order_backsights
;
686 if (strcmp(buffer
, "CORRECTIONS") == 0) {
688 pcs
->z
[Q_BEARING
] = -rad(read_numeric(fFalse
));
689 pcs
->z
[Q_GRADIENT
] = -rad(read_numeric(fFalse
));
690 pcs
->z
[Q_LENGTH
] = -read_numeric(fFalse
);
692 pcs
->z
[Q_BEARING
] = 0;
693 pcs
->z
[Q_GRADIENT
] = 0;
694 pcs
->z
[Q_LENGTH
] = 0;
718 settings
*pcsParent
= pcs
->next
;
719 SVX_ASSERT(pcsParent
);
720 pcs
->ordering
= NULL
;
724 } else if (fmt
== FMT_MAK
) {
725 while (ch
!= EOF
&& !ferror(file
.fh
)) {
729 char *dat_pth
= path_from_fnm(file
.filename
);
730 char *dat_fnm
= NULL
;
732 nextch_handling_eol();
733 while (ch
!= ',' && ch
!= ';' && ch
!= EOF
) {
734 while (isEol(ch
)) process_eol();
735 s_catchar(&dat_fnm
, &dat_fnm_len
, (char)ch
);
736 nextch_handling_eol();
738 while (ch
!= ';' && ch
!= EOF
) {
740 nextch_handling_eol();
741 name
= read_prefix(PFX_STATION
|PFX_OPT
);
748 bool in_feet
= fFalse
;
749 name
->sflags
|= BIT(SFLAGS_FIXED
);
750 nextch_handling_eol();
751 if (ch
== 'F' || ch
== 'f') {
753 nextch_handling_eol();
754 } else if (ch
== 'M' || ch
== 'm') {
755 nextch_handling_eol();
757 compile_diagnostic(DIAG_ERR
, /*Expecting āFā or āMā*/103);
759 while (!isdigit(ch
) && ch
!= '+' && ch
!= '-' &&
760 ch
!= '.' && ch
!= ']' && ch
!= EOF
) {
761 nextch_handling_eol();
763 x
= read_numeric(fFalse
);
764 while (!isdigit(ch
) && ch
!= '+' && ch
!= '-' &&
765 ch
!= '.' && ch
!= ']' && ch
!= EOF
) {
766 nextch_handling_eol();
768 y
= read_numeric(fFalse
);
769 while (!isdigit(ch
) && ch
!= '+' && ch
!= '-' &&
770 ch
!= '.' && ch
!= ']' && ch
!= EOF
) {
771 nextch_handling_eol();
773 z
= read_numeric(fFalse
);
775 x
*= METRES_PER_FOOT
;
776 y
*= METRES_PER_FOOT
;
777 z
*= METRES_PER_FOOT
;
779 stn
= StnFromPfx(name
);
786 if (x
!= POS(stn
, 0) || y
!= POS(stn
, 1) ||
788 compile_diagnostic(DIAG_ERR
, /*Station already fixed or equated to a fixed point*/46);
790 compile_diagnostic(DIAG_WARN
, /*Station already fixed at the same coordinates*/55);
793 while (ch
!= ']' && ch
!= EOF
) nextch_handling_eol();
795 nextch_handling_eol();
799 /* FIXME: link station - ignore for now */
800 /* FIXME: perhaps issue warning? Other station names can be "reused", which is problematic... */
802 while (ch
!= ',' && ch
!= ';' && ch
!= EOF
)
803 nextch_handling_eol();
808 data_file(dat_pth
, dat_fnm
);
813 /* FIXME: also check for % and $ later */
814 nextch_handling_eol();
818 settings
*pcsParent
= pcs
->next
;
819 SVX_ASSERT(pcsParent
);
824 while (ch
!= EOF
&& !ferror(file
.fh
)) {
825 if (!process_non_data_line()) {
826 f_export_ok
= fFalse
;
827 switch (pcs
->style
) {
833 case STYLE_CARTESIAN
:
853 /* don't allow *BEGIN at the end of a file, then *EXPORT in the
855 f_export_ok
= fFalse
;
857 if (pcs
->begin_lineno
) {
858 error_in_file(file
.filename
, pcs
->begin_lineno
,
859 /*BEGIN with no matching END in this file*/23);
860 /* Implicitly close any unclosed BEGINs from this file */
862 settings
*pcsParent
= pcs
->next
;
863 SVX_ASSERT(pcsParent
);
866 } while (pcs
->begin_lineno
);
869 pcs
->begin_lineno
= begin_lineno_store
;
872 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
874 (void)fclose(file
.fh
);
878 /* don't free this - it may be pointed to by prefix.file */
879 /* osfree(file.filename); */
885 return a
- floor(a
/ (2 * M_PI
)) * (2 * M_PI
);
889 handle_plumb(clino_type
*p_ctype
)
892 CLINO_NULL
=-1, CLINO_UP
, CLINO_DOWN
, CLINO_LEVEL
894 static const sztok clino_tab
[] = {
896 {"DOWN", CLINO_DOWN
},
898 {"LEVEL", CLINO_LEVEL
},
903 static const real clinos
[] = {(real
)M_PI_2
, (real
)(-M_PI_2
), (real
)0.0};
911 tok
= match_tok(clino_tab
, TABSIZE(clino_tab
));
912 if (tok
!= CLINO_NULL
) {
913 *p_ctype
= (tok
== CLINO_LEVEL
? CTYPE_HORIZ
: CTYPE_PLUMB
);
917 } else if (isSign(ch
)) {
920 if (toupper(ch
) == 'V') {
922 *p_ctype
= CTYPE_PLUMB
;
923 return (!isMinus(chOld
) ? M_PI_2
: -M_PI_2
);
927 *p_ctype
= CTYPE_OMIT
;
928 /* no clino reading, so assume 0 with large sd */
931 } else if (isOmit(ch
)) {
932 /* OMIT char may not be a SIGN char too so we need to check here as
933 * well as above... */
935 *p_ctype
= CTYPE_OMIT
;
936 /* no clino reading, so assume 0 with large sd */
943 warn_readings_differ(int msgno
, real diff
, int units
)
947 diff
/= get_units_factor(units
);
948 sprintf(buf
, "%.2f", fabs(diff
));
949 for (p
= buf
; *p
; ++p
) {
953 if (*p
!= '0') z
= p
+ 1;
959 strcpy(p
, get_units_string(units
));
960 compile_diagnostic(DIAG_WARN
, msgno
, buf
);
964 handle_comp_units(void)
966 bool fNoComp
= fTrue
;
967 if (VAL(Comp
) != HUGE_REAL
) {
969 VAL(Comp
) *= pcs
->units
[Q_BEARING
];
970 if (VAL(Comp
) < (real
)0.0 || VAL(Comp
) - M_PI
* 2.0 > EPSILON
) {
971 /* TRANSLATORS: Suspicious means something like 410 degrees or -20
973 compile_diagnostic_reading(DIAG_WARN
, Comp
, /*Suspicious compass reading*/59);
974 VAL(Comp
) = mod2pi(VAL(Comp
));
977 if (VAL(BackComp
) != HUGE_REAL
) {
979 VAL(BackComp
) *= pcs
->units
[Q_BACKBEARING
];
980 if (VAL(BackComp
) < (real
)0.0 || VAL(BackComp
) - M_PI
* 2.0 > EPSILON
) {
981 /* FIXME: different message for BackComp? */
982 compile_diagnostic_reading(DIAG_WARN
, BackComp
, /*Suspicious compass reading*/59);
983 VAL(BackComp
) = mod2pi(VAL(BackComp
));
990 handle_compass(real
*p_var
)
992 real compvar
= VAR(Comp
);
993 real comp
= VAL(Comp
);
994 real backcomp
= VAL(BackComp
);
996 if (pcs
->z
[Q_DECLINATION
] != HUGE_REAL
) {
997 declination
= -pcs
->z
[Q_DECLINATION
];
998 } else if (pcs
->declination
!= HUGE_REAL
) {
999 /* Cached value calculated for a previous compass reading taken on the
1000 * same date (by the 'else' just below).
1002 declination
= pcs
->declination
;
1004 if (!pcs
->meta
|| pcs
->meta
->days1
== -1) {
1005 compile_diagnostic(DIAG_WARN
, /*No survey date specified - using 0 for magnetic declination*/304);
1008 int avg_days
= (pcs
->meta
->days1
+ pcs
->meta
->days2
) / 2;
1009 double dat
= julian_date_from_days_since_1900(avg_days
);
1010 /* thgeomag() takes (lat, lon, h, dat) - i.e. (y, x, z, date). */
1011 declination
= thgeomag(pcs
->dec_y
, pcs
->dec_x
, pcs
->dec_z
, dat
);
1013 declination
-= pcs
->convergence
;
1014 /* We cache the calculated declination as the calculation is relatively
1015 * expensive. We also cache an "assumed 0" answer so that we only
1016 * warn once per such survey rather than for every line with a compass
1018 pcs
->declination
= declination
;
1020 if (comp
!= HUGE_REAL
) {
1021 comp
= (comp
- pcs
->z
[Q_BEARING
]) * pcs
->sc
[Q_BEARING
];
1022 comp
+= declination
;
1024 if (backcomp
!= HUGE_REAL
) {
1025 backcomp
= (backcomp
- pcs
->z
[Q_BACKBEARING
])
1026 * pcs
->sc
[Q_BACKBEARING
];
1027 backcomp
+= declination
;
1029 if (comp
!= HUGE_REAL
) {
1030 real diff
= comp
- backcomp
;
1031 real adj
= fabs(diff
) > M_PI
? M_PI
: 0;
1032 diff
-= floor((diff
+ M_PI
) / (2 * M_PI
)) * 2 * M_PI
;
1033 if (sqrd(diff
/ 3.0) > compvar
+ VAR(BackComp
)) {
1034 /* fore and back readings differ by more than 3 sds */
1035 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1036 * by, e.g. "2.5Ā°" or "3įµ". */
1037 warn_readings_differ(/*COMPASS reading and BACKCOMPASS reading disagree by %s*/98,
1038 diff
, get_angle_units(Q_BEARING
));
1040 comp
= (comp
/ compvar
+ backcomp
/ VAR(BackComp
));
1041 compvar
= (compvar
+ VAR(BackComp
)) / 4;
1046 compvar
= VAR(BackComp
);
1054 handle_clino(q_quantity q
, reading r
, real val
, bool percent
, clino_type
*p_ctype
)
1058 real diff_from_abs90
;
1059 val
*= pcs
->units
[q
];
1060 /* percentage scale */
1061 if (percent
) val
= atan(val
);
1062 /* We want to warn if there's a reading which it would be impossible
1063 * to have read from the instrument (e.g. on a -90 to 90 degree scale
1064 * you can't read "96" (it's probably a typo for "69"). However, the
1065 * gradient reading from a topofil is typically in the range 0 to 180,
1066 * with 90 being horizontal.
1068 * Really we should allow the valid range to be specified, but for now
1069 * we infer it from the zero error - if this is within 45 degrees of
1070 * 90 then we assume the range is 0 to 180.
1073 range_0_180
= (z
> M_PI_4
&& z
< 3*M_PI_4
);
1074 diff_from_abs90
= fabs(val
) - M_PI_2
;
1075 if (diff_from_abs90
> EPSILON
) {
1077 int clino_units
= get_angle_units(q
);
1078 const char * units
= get_units_string(clino_units
);
1079 real right_angle
= M_PI_2
/ get_units_factor(clino_units
);
1080 /* FIXME: different message for BackClino? */
1081 /* TRANSLATORS: %.f%s will be replaced with a right angle in the
1082 * units currently in use, e.g. "90Ā°" or "100įµ". And "absolute
1083 * value" means the reading ignoring the sign (so it might be
1084 * < -90Ā° or > 90Ā°. */
1085 compile_diagnostic_reading(DIAG_WARN
, r
, /*Clino reading over %.f%s (absolute value)*/51,
1086 right_angle
, units
);
1088 } else if (TSTBIT(pcs
->infer
, INFER_PLUMBS
) &&
1089 diff_from_abs90
>= -EPSILON
) {
1090 *p_ctype
= CTYPE_INFERPLUMB
;
1092 if (range_0_180
&& *p_ctype
!= CTYPE_INFERPLUMB
) {
1093 /* FIXME: Warning message not ideal... */
1094 if (val
< 0.0 || val
- M_PI
> EPSILON
) {
1095 int clino_units
= get_angle_units(q
);
1096 const char * units
= get_units_string(clino_units
);
1097 real right_angle
= M_PI_2
/ get_units_factor(clino_units
);
1098 compile_diagnostic_reading(DIAG_WARN
, r
, /*Clino reading over %.f%s (absolute value)*/51,
1099 right_angle
, units
);
1106 process_normal(prefix
*fr
, prefix
*to
, bool fToFirst
,
1107 clino_type ctype
, clino_type backctype
)
1109 real tape
= VAL(Tape
);
1110 real clin
= VAL(Clino
);
1111 real backclin
= VAL(BackClino
);
1115 #ifndef NO_COVARIANCES
1121 /* adjusted tape is negative -- probably the calibration is wrong */
1122 if (tape
< (real
)0.0) {
1123 /* TRANSLATE different message for topofil? */
1124 compile_diagnostic_reading(DIAG_WARN
, Tape
, /*Negative adjusted tape reading*/79);
1127 fNoComp
= handle_comp_units();
1129 if (ctype
== CTYPE_READING
) {
1130 clin
= handle_clino(Q_GRADIENT
, Clino
, clin
,
1131 pcs
->f_clino_percent
, &ctype
);
1134 if (backctype
== CTYPE_READING
) {
1135 backclin
= handle_clino(Q_BACKGRADIENT
, BackClino
, backclin
,
1136 pcs
->f_backclino_percent
, &backctype
);
1139 /* un-infer the plumb if the backsight was just a reading */
1140 if (ctype
== CTYPE_INFERPLUMB
&& backctype
== CTYPE_READING
) {
1141 ctype
= CTYPE_READING
;
1144 if (ctype
!= CTYPE_OMIT
&& backctype
!= CTYPE_OMIT
&& ctype
!= backctype
) {
1145 /* TRANSLATORS: In data with backsights, the user has tried to give a
1146 * plumb for the foresight and a clino reading for the backsight, or
1147 * something similar. */
1148 compile_error_reading_skip(Clino
, /*CLINO and BACKCLINO readings must be of the same type*/84);
1152 if (ctype
== CTYPE_PLUMB
|| ctype
== CTYPE_INFERPLUMB
||
1153 backctype
== CTYPE_PLUMB
|| backctype
== CTYPE_INFERPLUMB
) {
1156 if (ctype
== CTYPE_PLUMB
||
1157 (ctype
== CTYPE_INFERPLUMB
&& VAL(Comp
) != 0.0) ||
1158 backctype
== CTYPE_PLUMB
||
1159 (backctype
== CTYPE_INFERPLUMB
&& VAL(BackComp
) != 0.0)) {
1160 /* FIXME: Different message for BackComp? */
1161 /* TRANSLATORS: A "plumbed leg" is one measured using a plumbline
1162 * (a weight on a string). So the problem here is that the leg is
1163 * vertical, so a compass reading has no meaning! */
1164 compile_diagnostic(DIAG_WARN
, /*Compass reading given on plumbed leg*/21);
1168 dx
= dy
= (real
)0.0;
1169 if (ctype
!= CTYPE_OMIT
) {
1170 if (backctype
!= CTYPE_OMIT
&& (clin
> 0) == (backclin
> 0)) {
1171 /* TRANSLATORS: We've been told the foresight and backsight are
1172 * both "UP", or that they're both "DOWN". */
1173 compile_error_reading_skip(Clino
, /*Plumbed CLINO and BACKCLINO readings can't be in the same direction*/92);
1176 dz
= (clin
> (real
)0.0) ? tape
: -tape
;
1178 dz
= (backclin
< (real
)0.0) ? tape
: -tape
;
1180 vx
= vy
= var(Q_POS
) / 3.0 + dz
* dz
* var(Q_PLUMB
);
1181 vz
= var(Q_POS
) / 3.0 + VAR(Tape
);
1182 #ifndef NO_COVARIANCES
1183 /* Correct values - no covariances in this case! */
1184 cxy
= cyz
= czx
= (real
)0.0;
1187 /* Each of ctype and backctype are either CTYPE_READING/CTYPE_HORIZ
1190 real L2
, cosG
, LcosG
, cosG2
, sinB
, cosB
, dx2
, dy2
, dz2
, v
, V
;
1192 /* TRANSLATORS: Here "legs" are survey legs, i.e. measurements between
1193 * survey stations. */
1194 compile_error_reading_skip(Comp
, /*Compass reading may not be omitted except on plumbed legs*/14);
1197 if (tape
== (real
)0.0) {
1198 dx
= dy
= dz
= (real
)0.0;
1199 vx
= vy
= vz
= (real
)(var(Q_POS
) / 3.0); /* Position error only */
1200 #ifndef NO_COVARIANCES
1201 cxy
= cyz
= czx
= (real
)0.0;
1204 printf("Zero length leg: vx = %f, vy = %f, vz = %f\n", vx
, vy
, vz
);
1208 /* take into account variance in LEVEL case */
1209 real var_clin
= var(Q_LEVEL
);
1211 real comp
= handle_compass(&var_comp
);
1212 /* ctype != CTYPE_READING is LEVEL case */
1213 if (ctype
== CTYPE_READING
) {
1214 clin
= (clin
- pcs
->z
[Q_GRADIENT
]) * pcs
->sc
[Q_GRADIENT
];
1215 var_clin
= VAR(Clino
);
1217 if (backctype
== CTYPE_READING
) {
1218 backclin
= (backclin
- pcs
->z
[Q_BACKGRADIENT
])
1219 * pcs
->sc
[Q_BACKGRADIENT
];
1220 if (ctype
== CTYPE_READING
) {
1221 if (sqrd((clin
+ backclin
) / 3.0) > var_clin
+ VAR(BackClino
)) {
1222 /* fore and back readings differ by more than 3 sds */
1223 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1224 * by, e.g. "2.5Ā°" or "3įµ". */
1225 warn_readings_differ(/*CLINO reading and BACKCLINO reading disagree by %s*/99,
1226 clin
+ backclin
, get_angle_units(Q_GRADIENT
));
1228 clin
= (clin
/ var_clin
- backclin
/ VAR(BackClino
));
1229 var_clin
= (var_clin
+ VAR(BackClino
)) / 4;
1233 var_clin
= VAR(BackClino
);
1238 printf(" %4.2f %4.2f %4.2f\n", tape
, comp
, clin
);
1241 LcosG
= tape
* cosG
;
1245 printf("sinB = %f, cosG = %f, LcosG = %f\n", sinB
, cosG
, LcosG
);
1249 dz
= tape
* sin(clin
);
1250 /* printf("%.2f\n",clin); */
1252 printf("dx = %f\ndy = %f\ndz = %f\n", dx
, dy
, dz
);
1258 cosG2
= cosG
* cosG
;
1259 sinGcosG
= sin(clin
) * cosG
;
1262 #ifdef NO_COVARIANCES
1263 vx
= (var(Q_POS
) / 3.0 + dx2
* V
+ dy2
* var_comp
+
1264 (.5 + sinB
* sinB
* cosG2
) * v
);
1265 vy
= (var(Q_POS
) / 3.0 + dy2
* V
+ dx2
* var_comp
+
1266 (.5 + cosB
* cosB
* cosG2
) * v
);
1267 if (ctype
== CTYPE_OMIT
&& backctype
== CTYPE_OMIT
) {
1268 /* if no clino, assume sd=tape/sqrt(10) so 3sds = .95*tape */
1269 vz
= var(Q_POS
) / 3.0 + L2
* (real
)0.1;
1271 vz
= var(Q_POS
) / 3.0 + dz2
* V
+ L2
* cosG2
* var_clin
;
1273 /* for Surveyor87 errors: vx=vy=vz=var(Q_POS)/3.0; */
1275 vx
= var(Q_POS
) / 3.0 + dx2
* V
+ dy2
* var_comp
+
1277 vy
= var(Q_POS
) / 3.0 + dy2
* V
+ dx2
* var_comp
+
1279 if (ctype
== CTYPE_OMIT
&& backctype
== CTYPE_OMIT
) {
1280 /* if no clino, assume sd=tape/sqrt(10) so 3sds = .95*tape */
1281 vz
= var(Q_POS
) / 3.0 + L2
* (real
)0.1;
1283 vz
= var(Q_POS
) / 3.0 + dz2
* V
+ L2
* cosG2
* var_clin
;
1285 /* usual covariance formulae are fine in no clino case since
1286 * dz = 0 so value of var_clin is ignored */
1287 cxy
= sinB
* cosB
* (VAR(Tape
) * cosG2
+ var_clin
* dz2
)
1288 - var_comp
* dx
* dy
;
1289 czx
= VAR(Tape
) * sinB
* sinGcosG
- var_clin
* dx
* dz
;
1290 cyz
= VAR(Tape
) * cosB
* sinGcosG
- var_clin
* dy
* dz
;
1292 printf("vx = %6.3f, vy = %6.3f, vz = %6.3f\n", vx
, vy
, vz
);
1293 printf("cxy = %6.3f, cyz = %6.3f, czx = %6.3f\n", cxy
, cyz
, czx
);
1297 printf("In DATAIN.C, vx = %f, vy = %f, vz = %f\n", vx
, vy
, vz
);
1302 printf("Just before addleg, vx = %f\n", vx
);
1304 /*printf("dx,dy,dz = %.2f %.2f %.2f\n\n", dx, dy, dz);*/
1305 addlegbyname(fr
, to
, fToFirst
, dx
, dy
, dz
, vx
, vy
, vz
1306 #ifndef NO_COVARIANCES
1314 process_diving(prefix
*fr
, prefix
*to
, bool fToFirst
, bool fDepthChange
)
1316 real tape
= VAL(Tape
);
1320 #ifndef NO_COVARIANCES
1321 real cxy
= 0, cyz
= 0, czx
= 0;
1324 handle_comp_units();
1326 /* depth gauge readings increase upwards with default calibration */
1328 SVX_ASSERT(VAL(FrDepth
) == 0.0);
1329 dz
= VAL(ToDepth
) * pcs
->units
[Q_DEPTH
] - pcs
->z
[Q_DEPTH
];
1330 dz
*= pcs
->sc
[Q_DEPTH
];
1332 dz
= VAL(ToDepth
) - VAL(FrDepth
);
1333 dz
*= pcs
->units
[Q_DEPTH
] * pcs
->sc
[Q_DEPTH
];
1336 /* adjusted tape is negative -- probably the calibration is wrong */
1337 if (tape
< (real
)0.0) {
1338 compile_diagnostic(DIAG_WARN
, /*Negative adjusted tape reading*/79);
1341 /* check if tape is less than depth change */
1342 if (tape
< fabs(dz
)) {
1343 /* FIXME: allow margin of error based on variances? */
1344 /* TRANSLATORS: This means that the data fed in said this.
1346 * It could be a gross error (e.g. the decimal point is missing from the
1347 * depth gauge reading) or it could just be due to random error on a near
1349 compile_diagnostic(DIAG_WARN
, /*Tape reading is less than change in depth*/62);
1352 if (tape
== (real
)0.0 && dz
== 0.0) {
1353 dx
= dy
= dz
= (real
)0.0;
1354 vx
= vy
= vz
= (real
)(var(Q_POS
) / 3.0); /* Position error only */
1355 } else if (VAL(Comp
) == HUGE_REAL
&&
1356 VAL(BackComp
) == HUGE_REAL
) {
1358 dx
= dy
= (real
)0.0;
1359 if (dz
< 0) tape
= -tape
;
1360 /* FIXME: Should use FrDepth sometimes... */
1361 dz
= (dz
* VAR(Tape
) + tape
* 2 * VAR(ToDepth
))
1362 / (VAR(Tape
) * 2 * VAR(ToDepth
));
1363 vx
= vy
= var(Q_POS
) / 3.0 + dz
* dz
* var(Q_PLUMB
);
1364 /* FIXME: Should use FrDepth sometimes... */
1365 vz
= var(Q_POS
) / 3.0 + VAR(Tape
) * 2 * VAR(ToDepth
)
1366 / (VAR(Tape
) + VAR(ToDepth
));
1368 real L2
, sinB
, cosB
, dz2
, D2
;
1370 real comp
= handle_compass(&var_comp
);
1376 if (D2
<= (real
)0.0) {
1377 /* FIXME: Should use FrDepth sometimes... */
1378 real vsum
= VAR(Tape
) + 2 * VAR(ToDepth
);
1379 dx
= dy
= (real
)0.0;
1380 vx
= vy
= var(Q_POS
) / 3.0;
1381 /* FIXME: Should use FrDepth sometimes... */
1382 vz
= var(Q_POS
) / 3.0 + VAR(Tape
) * 2 * VAR(ToDepth
) / vsum
;
1384 /* FIXME: Should use FrDepth sometimes... */
1385 dz
= (dz
* VAR(Tape
) + tape
* 2 * VAR(ToDepth
)) / vsum
;
1387 dz
= (dz
* VAR(Tape
) - tape
* 2 * VAR(ToDepth
)) / vsum
;
1391 /* FIXME: Should use FrDepth sometimes... */
1392 real F
= VAR(Tape
) * L2
+ 2 * VAR(ToDepth
) * D2
;
1396 vx
= var(Q_POS
) / 3.0 +
1397 sinB
* sinB
* F
/ D2
+ var_comp
* dy
* dy
;
1398 vy
= var(Q_POS
) / 3.0 +
1399 cosB
* cosB
* F
/ D2
+ var_comp
* dx
* dx
;
1400 /* FIXME: Should use FrDepth sometimes... */
1401 vz
= var(Q_POS
) / 3.0 + 2 * VAR(ToDepth
);
1403 #ifndef NO_COVARIANCES
1404 cxy
= sinB
* cosB
* (F
/ D2
+ var_comp
* D2
);
1405 /* FIXME: Should use FrDepth sometimes... */
1406 cyz
= -2 * VAR(ToDepth
) * dy
/ D
;
1407 czx
= -2 * VAR(ToDepth
) * dx
/ D
;
1410 /* FIXME: If there's a clino reading, check it against the depth reading,
1412 * if (VAL(Clino) != HUGE_REAL || VAL(BackClino) != HUGE_REAL) { ... }
1415 addlegbyname(fr
, to
, fToFirst
, dx
, dy
, dz
, vx
, vy
, vz
1416 #ifndef NO_COVARIANCES
1424 process_cartesian(prefix
*fr
, prefix
*to
, bool fToFirst
)
1426 real dx
= (VAL(Dx
) * pcs
->units
[Q_DX
] - pcs
->z
[Q_DX
]) * pcs
->sc
[Q_DX
];
1427 real dy
= (VAL(Dy
) * pcs
->units
[Q_DY
] - pcs
->z
[Q_DY
]) * pcs
->sc
[Q_DY
];
1428 real dz
= (VAL(Dz
) * pcs
->units
[Q_DZ
] - pcs
->z
[Q_DZ
]) * pcs
->sc
[Q_DZ
];
1430 addlegbyname(fr
, to
, fToFirst
, dx
, dy
, dz
, VAR(Dx
), VAR(Dy
), VAR(Dz
)
1431 #ifndef NO_COVARIANCES
1439 data_cartesian(void)
1441 prefix
*fr
= NULL
, *to
= NULL
;
1443 bool fMulti
= fFalse
;
1445 reading first_stn
= End
;
1447 const reading
*ordering
;
1451 for (ordering
= pcs
->ordering
; ; ordering
++) {
1453 switch (*ordering
) {
1455 fr
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
);
1456 if (first_stn
== End
) first_stn
= Fr
;
1459 to
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
);
1460 if (first_stn
== End
) first_stn
= To
;
1464 to
= read_prefix(PFX_STATION
);
1467 case Dx
: case Dy
: case Dz
:
1468 read_reading(*ordering
, fFalse
);
1472 case IgnoreAllAndNewLine
:
1477 if (!process_cartesian(fr
, to
, first_stn
== To
))
1484 if (isData(ch
)) break;
1495 process_cartesian(fr
, to
, first_stn
== To
);
1502 } while (isComm(ch
));
1504 default: BUG("Unknown reading in ordering");
1510 process_cylpolar(prefix
*fr
, prefix
*to
, bool fToFirst
, bool fDepthChange
)
1512 real tape
= VAL(Tape
);
1516 #ifndef NO_COVARIANCES
1520 handle_comp_units();
1522 /* depth gauge readings increase upwards with default calibration */
1524 SVX_ASSERT(VAL(FrDepth
) == 0.0);
1525 dz
= VAL(ToDepth
) * pcs
->units
[Q_DEPTH
] - pcs
->z
[Q_DEPTH
];
1526 dz
*= pcs
->sc
[Q_DEPTH
];
1528 dz
= VAL(ToDepth
) - VAL(FrDepth
);
1529 dz
*= pcs
->units
[Q_DEPTH
] * pcs
->sc
[Q_DEPTH
];
1532 /* adjusted tape is negative -- probably the calibration is wrong */
1533 if (tape
< (real
)0.0) {
1534 compile_diagnostic(DIAG_WARN
, /*Negative adjusted tape reading*/79);
1537 if (VAL(Comp
) == HUGE_REAL
&& VAL(BackComp
) == HUGE_REAL
) {
1539 dx
= dy
= (real
)0.0;
1540 vx
= vy
= var(Q_POS
) / 3.0 + dz
* dz
* var(Q_PLUMB
);
1541 /* FIXME: Should use FrDepth sometimes... */
1542 vz
= var(Q_POS
) / 3.0 + 2 * VAR(ToDepth
);
1546 real comp
= handle_compass(&var_comp
);
1553 vx
= var(Q_POS
) / 3.0 +
1554 VAR(Tape
) * sinB
* sinB
+ var_comp
* dy
* dy
;
1555 vy
= var(Q_POS
) / 3.0 +
1556 VAR(Tape
) * cosB
* cosB
+ var_comp
* dx
* dx
;
1557 /* FIXME: Should use FrDepth sometimes... */
1558 vz
= var(Q_POS
) / 3.0 + 2 * VAR(ToDepth
);
1560 #ifndef NO_COVARIANCES
1561 cxy
= (VAR(Tape
) - var_comp
* tape
* tape
) * sinB
* cosB
;
1564 addlegbyname(fr
, to
, fToFirst
, dx
, dy
, dz
, vx
, vy
, vz
1565 #ifndef NO_COVARIANCES
1572 /* Process tape/compass/clino, diving, and cylpolar styles of survey data
1573 * Also handles topofil (fromcount/tocount or count) in place of tape */
1577 prefix
*fr
= NULL
, *to
= NULL
;
1578 reading first_stn
= End
;
1580 bool fTopofil
= fFalse
, fMulti
= fFalse
;
1582 clino_type ctype
, backctype
;
1584 unsigned long compass_dat_flags
= 0;
1586 const reading
*ordering
;
1588 VAL(Tape
) = VAL(BackTape
) = HUGE_REAL
;
1589 VAL(Comp
) = VAL(BackComp
) = HUGE_REAL
;
1590 VAL(FrCount
) = VAL(ToCount
) = 0;
1591 VAL(FrDepth
) = VAL(ToDepth
) = 0;
1592 VAL(Left
) = VAL(Right
) = VAL(Up
) = VAL(Down
) = HUGE_REAL
;
1595 ctype
= backctype
= CTYPE_OMIT
;
1596 fDepthChange
= fFalse
;
1598 /* ordering may omit clino reading, so set up default here */
1599 /* this is also used if clino reading is the omit character */
1600 VAL(Clino
) = VAL(BackClino
) = 0;
1604 /* We clear these flags in the normal course of events, but if there's an
1605 * error in a reading, we might not, so make sure it has been cleared here.
1607 pcs
->flags
&= ~(BIT(FLAGS_ANON_ONE_END
) | BIT(FLAGS_IMPLICIT_SPLAY
));
1608 for (ordering
= pcs
->ordering
; ; ordering
++) {
1610 switch (*ordering
) {
1612 fr
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
|PFX_ANON
);
1613 if (first_stn
== End
) first_stn
= Fr
;
1616 to
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
|PFX_ANON
);
1617 if (first_stn
== End
) first_stn
= To
;
1621 to
= read_prefix(PFX_STATION
);
1626 DIR_NULL
=-1, DIR_FORE
, DIR_BACK
1628 static const sztok dir_tab
[] = {
1634 tok
= match_tok(dir_tab
, TABSIZE(dir_tab
));
1642 compile_diagnostic(DIAG_ERR
|DIAG_BUF
|DIAG_SKIP
, /*Found ā%sā, expecting āFā or āBā*/131, buffer
);
1648 case Tape
: case BackTape
: {
1649 reading r
= *ordering
;
1650 read_reading(r
, fTrue
);
1651 if (VAL(r
) == HUGE_REAL
) {
1653 compile_diagnostic_token_show(DIAG_ERR
, /*Expecting numeric field, found ā%sā*/9);
1654 /* Avoid also warning about omitted tape reading. */
1659 } else if (VAL(r
) < (real
)0.0) {
1660 compile_diagnostic_reading(DIAG_WARN
, r
, /*Negative tape reading*/60);
1665 VAL(FrCount
) = VAL(ToCount
);
1666 LOC(FrCount
) = LOC(ToCount
);
1667 WID(FrCount
) = WID(ToCount
);
1668 read_reading(ToCount
, fFalse
);
1672 read_reading(FrCount
, fFalse
);
1675 read_reading(ToCount
, fFalse
);
1678 case Comp
: case BackComp
:
1679 read_bearing_or_omit(*ordering
);
1681 case Clino
: case BackClino
: {
1682 reading r
= *ordering
;
1683 clino_type
* p_ctype
= (r
== Clino
? &ctype
: &backctype
);
1684 read_reading(r
, fTrue
);
1685 if (VAL(r
) == HUGE_REAL
) {
1686 VAL(r
) = handle_plumb(p_ctype
);
1687 if (VAL(r
) != HUGE_REAL
) break;
1688 compile_diagnostic_token_show(DIAG_ERR
, /*Expecting numeric field, found ā%sā*/9);
1693 *p_ctype
= CTYPE_READING
;
1696 case FrDepth
: case ToDepth
:
1697 read_reading(*ordering
, fFalse
);
1700 VAL(FrDepth
) = VAL(ToDepth
);
1701 LOC(FrDepth
) = LOC(ToDepth
);
1702 WID(FrDepth
) = WID(ToDepth
);
1703 read_reading(ToDepth
, fFalse
);
1706 fDepthChange
= fTrue
;
1708 read_reading(ToDepth
, fFalse
);
1710 case CompassDATComp
:
1711 read_bearing_or_omit(Comp
);
1712 if (is_compass_NaN(VAL(Comp
))) VAL(Comp
) = HUGE_REAL
;
1714 case CompassDATBackComp
:
1715 read_bearing_or_omit(BackComp
);
1716 if (is_compass_NaN(VAL(BackComp
))) VAL(BackComp
) = HUGE_REAL
;
1718 case CompassDATClino
: case CompassDATBackClino
: {
1720 clino_type
* p_ctype
;
1721 if (*ordering
== CompassDATClino
) {
1726 p_ctype
= &backctype
;
1728 read_reading(r
, fFalse
);
1729 if (is_compass_NaN(VAL(r
))) {
1731 *p_ctype
= CTYPE_OMIT
;
1733 *p_ctype
= CTYPE_READING
;
1737 case CompassDATLeft
: case CompassDATRight
:
1738 case CompassDATUp
: case CompassDATDown
: {
1739 /* FIXME: need to actually make use of these entries! */
1740 reading actual
= Left
+ (*ordering
- CompassDATLeft
);
1741 read_reading(actual
, fFalse
);
1742 if (VAL(actual
) < 0) VAL(actual
) = HUGE_REAL
;
1745 case CompassDATFlags
:
1752 while (ch
>= 'A' && ch
<= 'Z') {
1753 compass_dat_flags
|= BIT(ch
- 'A');
1754 /* We currently understand:
1755 * L (exclude from length)
1757 * FIXME: but should also handle at least some of:
1758 * C (no adjustment) (set all (co)variances to 0?)
1759 * P (no plot) (new flag in 3d for "hidden by default"?)
1766 compass_dat_flags
= 0;
1776 case IgnoreAllAndNewLine
:
1785 VAL(Tape
) = VAL(ToCount
) - VAL(FrCount
);
1786 LOC(Tape
) = LOC(ToCount
);
1787 WID(Tape
) = WID(ToCount
);
1789 /* Note: frdepth == todepth test works regardless of fDepthChange
1790 * (frdepth always zero, todepth is change of depth) and also
1791 * works for STYLE_NORMAL (both remain 0) */
1792 if (TSTBIT(pcs
->infer
, INFER_EQUATES
) &&
1793 (VAL(Tape
) == (real
)0.0 || VAL(Tape
) == HUGE_REAL
) &&
1794 (VAL(BackTape
) == (real
)0.0 || VAL(BackTape
) == HUGE_REAL
) &&
1795 VAL(FrDepth
) == VAL(ToDepth
)) {
1796 process_equate(fr
, to
);
1797 goto inferred_equate
;
1805 VAL(Tape
) *= pcs
->units
[Q_COUNT
] * pcs
->sc
[Q_COUNT
];
1806 } else if (VAL(Tape
) != HUGE_REAL
) {
1807 VAL(Tape
) *= pcs
->units
[Q_LENGTH
];
1808 VAL(Tape
) -= pcs
->z
[Q_LENGTH
];
1809 VAL(Tape
) *= pcs
->sc
[Q_LENGTH
];
1811 if (VAL(BackTape
) != HUGE_REAL
) {
1812 VAL(BackTape
) *= pcs
->units
[Q_BACKLENGTH
];
1813 VAL(BackTape
) -= pcs
->z
[Q_BACKLENGTH
];
1814 VAL(BackTape
) *= pcs
->sc
[Q_BACKLENGTH
];
1815 if (VAL(Tape
) != HUGE_REAL
) {
1816 real diff
= VAL(Tape
) - VAL(BackTape
);
1817 if (sqrd(diff
/ 3.0) > VAR(Tape
) + VAR(BackTape
)) {
1818 /* fore and back readings differ by more than 3 sds */
1819 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1820 * by, e.g. "0.12m" or "0.2ft". */
1821 warn_readings_differ(/*TAPE reading and BACKTAPE reading disagree by %s*/97,
1822 diff
, get_length_units(Q_LENGTH
));
1824 VAL(Tape
) = VAL(Tape
) / VAR(Tape
) + VAL(BackTape
) / VAR(BackTape
);
1825 VAR(Tape
) = (VAR(Tape
) + VAR(BackTape
)) / 4;
1826 VAL(Tape
) *= VAR(Tape
);
1828 VAL(Tape
) = VAL(BackTape
);
1829 VAR(Tape
) = VAR(BackTape
);
1831 } else if (VAL(Tape
) == HUGE_REAL
) {
1832 compile_diagnostic_reading(DIAG_ERR
, Tape
, /*Tape reading may not be omitted*/94);
1833 goto inferred_equate
;
1835 implicit_splay
= TSTBIT(pcs
->flags
, FLAGS_IMPLICIT_SPLAY
);
1836 pcs
->flags
&= ~(BIT(FLAGS_ANON_ONE_END
) | BIT(FLAGS_IMPLICIT_SPLAY
));
1837 save_flags
= pcs
->flags
;
1838 if (implicit_splay
) {
1839 pcs
->flags
|= BIT(FLAGS_SPLAY
);
1841 switch (pcs
->style
) {
1843 r
= process_normal(fr
, to
, (first_stn
== To
) ^ fRev
,
1847 /* FIXME: Handle any clino readings */
1848 r
= process_diving(fr
, to
, (first_stn
== To
) ^ fRev
,
1851 case STYLE_CYLPOLAR
:
1852 r
= process_cylpolar(fr
, to
, (first_stn
== To
) ^ fRev
,
1856 r
= 0; /* avoid warning */
1859 pcs
->flags
= save_flags
;
1862 /* Swap fr and to back to how they were for next line */
1871 ctype
= backctype
= CTYPE_OMIT
;
1872 fDepthChange
= fFalse
;
1874 /* ordering may omit clino reading, so set up default here */
1875 /* this is also used if clino reading is the omit character */
1876 VAL(Clino
) = VAL(BackClino
) = 0;
1877 LOC(Clino
) = LOC(BackClino
) = -1;
1878 WID(Clino
) = WID(BackClino
) = 0;
1886 if (isData(ch
)) break;
1899 /* Compass ignore flag is 'X' */
1900 if ((compass_dat_flags
& BIT('X' - 'A'))) {
1910 VAL(Tape
) = VAL(ToCount
) - VAL(FrCount
);
1911 LOC(Tape
) = LOC(ToCount
);
1912 WID(Tape
) = WID(ToCount
);
1914 /* Note: frdepth == todepth test works regardless of fDepthChange
1915 * (frdepth always zero, todepth is change of depth) and also
1916 * works for STYLE_NORMAL (both remain 0) */
1917 if (TSTBIT(pcs
->infer
, INFER_EQUATES
) &&
1918 (VAL(Tape
) == (real
)0.0 || VAL(Tape
) == HUGE_REAL
) &&
1919 (VAL(BackTape
) == (real
)0.0 || VAL(BackTape
) == HUGE_REAL
) &&
1920 VAL(FrDepth
) == VAL(ToDepth
)) {
1921 process_equate(fr
, to
);
1926 VAL(Tape
) *= pcs
->units
[Q_COUNT
] * pcs
->sc
[Q_COUNT
];
1927 } else if (VAL(Tape
) != HUGE_REAL
) {
1928 VAL(Tape
) *= pcs
->units
[Q_LENGTH
];
1929 VAL(Tape
) -= pcs
->z
[Q_LENGTH
];
1930 VAL(Tape
) *= pcs
->sc
[Q_LENGTH
];
1932 if (VAL(BackTape
) != HUGE_REAL
) {
1933 VAL(BackTape
) *= pcs
->units
[Q_BACKLENGTH
];
1934 VAL(BackTape
) -= pcs
->z
[Q_BACKLENGTH
];
1935 VAL(BackTape
) *= pcs
->sc
[Q_BACKLENGTH
];
1936 if (VAL(Tape
) != HUGE_REAL
) {
1937 real diff
= VAL(Tape
) - VAL(BackTape
);
1938 if (sqrd(diff
/ 3.0) > VAR(Tape
) + VAR(BackTape
)) {
1939 /* fore and back readings differ by more than 3 sds */
1940 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1941 * by, e.g. "0.12m" or "0.2ft". */
1942 warn_readings_differ(/*TAPE reading and BACKTAPE reading disagree by %s*/97,
1943 diff
, get_length_units(Q_LENGTH
));
1945 VAL(Tape
) = VAL(Tape
) / VAR(Tape
) + VAL(BackTape
) / VAR(BackTape
);
1946 VAR(Tape
) = (VAR(Tape
) + VAR(BackTape
)) / 4;
1947 VAL(Tape
) *= VAR(Tape
);
1949 VAL(Tape
) = VAL(BackTape
);
1950 VAR(Tape
) = VAR(BackTape
);
1952 } else if (VAL(Tape
) == HUGE_REAL
) {
1953 compile_diagnostic_reading(DIAG_ERR
, Tape
, /*Tape reading may not be omitted*/94);
1957 implicit_splay
= TSTBIT(pcs
->flags
, FLAGS_IMPLICIT_SPLAY
);
1958 pcs
->flags
&= ~(BIT(FLAGS_ANON_ONE_END
) | BIT(FLAGS_IMPLICIT_SPLAY
));
1959 save_flags
= pcs
->flags
;
1960 if (implicit_splay
) {
1961 pcs
->flags
|= BIT(FLAGS_SPLAY
);
1963 if ((compass_dat_flags
& BIT('L' - 'A'))) {
1964 /* 'L' means "exclude from length" - map this to Survex's
1965 * FLAGS_DUPLICATE. */
1966 pcs
->flags
|= BIT(FLAGS_DUPLICATE
);
1968 switch (pcs
->style
) {
1970 process_normal(fr
, to
, (first_stn
== To
) ^ fRev
,
1974 /* FIXME: Handle any clino readings */
1975 process_diving(fr
, to
, (first_stn
== To
) ^ fRev
,
1978 case STYLE_CYLPOLAR
:
1979 process_cylpolar(fr
, to
, (first_stn
== To
) ^ fRev
,
1985 pcs
->flags
= save_flags
;
1993 } while (isComm(ch
));
1996 BUG("Unknown reading in ordering");
2002 process_lrud(prefix
*stn
)
2004 SVX_ASSERT(next_lrud
);
2005 lrud
* xsect
= osnew(lrud
);
2007 xsect
->l
= (VAL(Left
) * pcs
->units
[Q_LEFT
] - pcs
->z
[Q_LEFT
]) * pcs
->sc
[Q_LEFT
];
2008 xsect
->r
= (VAL(Right
) * pcs
->units
[Q_RIGHT
] - pcs
->z
[Q_RIGHT
]) * pcs
->sc
[Q_RIGHT
];
2009 xsect
->u
= (VAL(Up
) * pcs
->units
[Q_UP
] - pcs
->z
[Q_UP
]) * pcs
->sc
[Q_UP
];
2010 xsect
->d
= (VAL(Down
) * pcs
->units
[Q_DOWN
] - pcs
->z
[Q_DOWN
]) * pcs
->sc
[Q_DOWN
];
2011 xsect
->meta
= pcs
->meta
;
2012 if (pcs
->meta
) ++pcs
->meta
->ref_count
;
2015 next_lrud
= &(xsect
->next
);
2024 const reading
*ordering
;
2026 for (ordering
= pcs
->ordering
; ; ordering
++) {
2028 switch (*ordering
) {
2030 stn
= read_prefix(PFX_STATION
);
2032 case Left
: case Right
: case Up
: case Down
: {
2033 reading r
= *ordering
;
2034 read_reading(r
, fTrue
);
2035 if (VAL(r
) == HUGE_REAL
) {
2037 compile_diagnostic_token_show(DIAG_ERR
, /*Expecting numeric field, found ā%sā*/9);
2055 default: BUG("Unknown reading in ordering");
2061 process_nosurvey(prefix
*fr
, prefix
*to
, bool fToFirst
)
2065 /* Suppress "unused fixed point" warnings for these stations */
2066 fr
->sflags
|= BIT(SFLAGS_USED
);
2067 to
->sflags
|= BIT(SFLAGS_USED
);
2069 /* add to linked list which is dealt with after network is solved */
2070 link
= osnew(nosurveylink
);
2072 link
->to
= StnFromPfx(to
);
2073 link
->fr
= StnFromPfx(fr
);
2075 link
->fr
= StnFromPfx(fr
);
2076 link
->to
= StnFromPfx(to
);
2078 link
->flags
= pcs
->flags
| (STYLE_NOSURVEY
<< FLAGS_STYLE_BIT0
);
2079 link
->meta
= pcs
->meta
;
2080 if (pcs
->meta
) ++pcs
->meta
->ref_count
;
2081 link
->next
= nosurveyhead
;
2082 nosurveyhead
= link
;
2089 prefix
*fr
= NULL
, *to
= NULL
;
2091 bool fMulti
= fFalse
;
2093 reading first_stn
= End
;
2095 const reading
*ordering
;
2099 for (ordering
= pcs
->ordering
; ; ordering
++) {
2101 switch (*ordering
) {
2103 fr
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
);
2104 if (first_stn
== End
) first_stn
= Fr
;
2107 to
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
);
2108 if (first_stn
== End
) first_stn
= To
;
2112 to
= read_prefix(PFX_STATION
);
2117 case IgnoreAllAndNewLine
:
2122 if (!process_nosurvey(fr
, to
, first_stn
== To
))
2125 if (ordering
[1] == End
) {
2129 } while (isComm(ch
));
2139 if (isData(ch
)) break;
2150 (void)process_nosurvey(fr
, to
, first_stn
== To
);
2157 } while (isComm(ch
));
2159 default: BUG("Unknown reading in ordering");
2164 /* totally ignore a line of survey data */