source: git/src/netskel.c @ ae275ef

RELEASE/1.0
Last change on this file since ae275ef was ae275ef, checked in by Olly Betts <olly@…>, 13 years ago

Backport change from 1.2.0:
src/netskel.c: In "Unused fixed point" warning, give file and
linenumber where the "*fix" occurred.

git-svn-id: file:///home/survex-svn/survex/branches/1.0@3719 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 26.8 KB
Line 
1/* netskel.c
2 * Survex network reduction - remove trailing traverses and concatenate
3 * traverses between junctions
4 * Copyright (C) 1991-2002,2005,2010 Olly Betts
5 *
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.
10 *
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.
15 *
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
19 */
20
21/* #define BLUNDER_DETECTION */
22
23#if 0
24#define DEBUG_INVALID 1
25#define VALIDATE 1
26#define DUMP_NETWORK 1
27#endif
28
29#ifdef HAVE_CONFIG_H
30# include <config.h>
31#endif
32
33#include "validate.h"
34#include "debug.h"
35#include "cavern.h"
36#include "filename.h"
37#include "message.h"
38#include "filelist.h"
39#include "netartic.h"
40#include "netbits.h"
41#include "netskel.h"
42#include "network.h"
43#include "out.h"
44
45#define sqrdd(X) (sqrd((X)[0]) + sqrd((X)[1]) + sqrd((X)[2]))
46
47typedef struct Stack {
48   struct Link *join1, *join2;
49   struct Stack *next;
50} stack;
51
52typedef struct StackTr {
53   struct Link *join1;
54   struct StackTr *next;
55} stackTrail;
56
57/* string used between things in traverse printouts eg \1 - \2 - \3 -...*/
58static const char *szLink = " - ";
59static const char *szLinkEq = " = "; /* use this one for equates */
60
61#if 0
62#define fprint_prefix(FH, NAME) BLK((fprint_prefix)((FH), (NAME));\
63                                    fprintf((FH), " [%p]", (void*)(NAME)); )
64#endif
65
66static stack *ptr; /* Ptr to TRaverse linked list for in-between travs */
67static stackTrail *ptrTrail; /* Ptr to TRaverse linked list for trail travs*/
68
69static void remove_trailing_travs(void);
70static void remove_travs(void);
71static void replace_travs(void);
72static void replace_trailing_travs(void);
73
74static void concatenate_trav(node *stn, int i);
75
76static void err_stat(int cLegsTrav, double lenTrav,
77                     double eTot, double eTotTheo,
78                     double hTot, double hTotTheo,
79                     double vTot, double vTotTheo);
80
81extern void
82solve_network(void /*node *stnlist*/)
83{
84   static int first_solve = 1;
85   node *stn;
86
87   if (stnlist == NULL) {
88      if (first_solve) fatalerror(/*No survey data*/43);
89      /* We've had a *solve followed by another *solve (or the implicit
90       * *solve at the end of the data.  Don't moan about that. */
91      return;
92   }
93   ptr = NULL;
94   ptrTrail = NULL;
95   dump_network();
96
97   /* If there are no fixed points, invent one.  Do this first to
98    * avoid problems with sub-nodes of the invented fix which have
99    * been removed.  It also means we can fix the "first" station,
100    * which makes more sense to the user. */
101   FOR_EACH_STN(stn, stnlist)
102      if (fixed(stn)) break;
103
104   if (!stn && first_solve) {
105     /* If we've had a *solve and all the new survey since then is hanging,
106      * we don't want to invent a fixed point.  We want to complain but
107      * the easiest way to is just to continue processing and let
108      * articulate() catch this condition as it will any hanging survey
109      * data. */
110      node *stnFirst = NULL;
111
112      /* New stations are pushed onto the head of the list, so the
113       * first station added is the last in the list. */
114      FOR_EACH_STN(stn, stnlist) {
115          /* Prefer a station with legs attached when choosing one to fix
116           * so that if there's a hanging station on a nosurvey leg we pick
117           * the main clump of survey data. */
118          if (stnFirst && !stnFirst->leg[0]) continue;
119          stnFirst = stn;
120      }
121
122      /* If we've got nosurvey legs, then the station we find to fix could have
123       * no real legs attached. */
124      SVX_ASSERT2(nosurveyhead || stnFirst->leg[0], "no fixed stns, but we've got a zero node!");
125      SVX_ASSERT2(stnFirst, "no stations left in net!");
126      stn = stnFirst;
127      printf(msg(/*Survey has no fixed points. Therefore I've fixed %s at (0,0,0)*/72),
128             sprint_prefix(stn->name));
129      putnl();
130      POS(stn,0) = (real)0.0;
131      POS(stn,1) = (real)0.0;
132      POS(stn,2) = (real)0.0;
133      fix(stn);
134   }
135
136   first_solve = 0;
137
138   remove_trailing_travs();
139   validate(); dump_network();
140   remove_travs();
141   validate(); dump_network();
142   remove_subnets();
143   validate(); dump_network();
144   articulate();
145   validate(); dump_network();
146   replace_subnets();
147   validate(); dump_network();
148   replace_travs();
149   validate(); dump_network();
150   replace_trailing_travs();
151   validate(); dump_network();
152}
153
154static void
155remove_trailing_travs(void)
156{
157   node *stn;
158   out_current_action(msg(/*Removing trailing traverses*/125));
159   FOR_EACH_STN(stn, stnlist) {
160      if (!fixed(stn) && one_node(stn)) {
161         int i = 0;
162         int j;
163         node *stn2 = stn;
164         stackTrail *trav;
165
166#if PRINT_NETBITS
167         printf("Removed trailing trav ");
168#endif
169         do {
170            struct Link *leg;
171#if PRINT_NETBITS
172            print_prefix(stn2->name); printf("<%p>",stn2); printf(szLink);
173#endif
174            remove_stn_from_list(&stnlist, stn2);
175            leg = stn2->leg[i];
176            j = reverse_leg_dirn(leg);
177            stn2 = leg->l.to;
178            i = j ^ 1; /* flip direction for other leg of 2 node */
179            /* stop if fixed or 3 or 1 node */
180         } while (two_node(stn2) && !fixed(stn2));
181
182         /* put traverse on stack */
183         trav = osnew(stackTrail);
184         trav->join1 = stn2->leg[j];
185         trav->next = ptrTrail;
186         ptrTrail = trav;
187
188         /* We want to keep all 2-nodes using legs 0 and 1 and all one nodes
189          * using leg 0 so we may need to swap leg j with leg 2 (for a 3 node)
190          * or leg 1 (for a fixed 2 node) */
191         if ((j == 0 && !one_node(stn2)) || (j == 1 && three_node(stn2))) {
192            /* i is the direction to swap with */
193            i = (three_node(stn2)) ? 2 : 1;
194            /* change the other direction of leg i to use leg j */
195            reverse_leg(stn2->leg[i])->l.reverse += j - i;
196            stn2->leg[j] = stn2->leg[i];
197            j = i;
198         }
199         stn2->leg[j] = NULL;
200
201#if PRINT_NETBITS
202         print_prefix(stn2->name); printf("<%p>",stn2); putnl();
203#endif
204      }
205   }
206}
207
208static void
209remove_travs(void)
210{
211   node *stn;
212   out_current_action(msg(/*Concatenating traverses between nodes*/126));
213   FOR_EACH_STN(stn, stnlist) {
214      if (fixed(stn) || three_node(stn)) {
215         int d;
216         for (d = 0; d <= 2; d++) {
217            linkfor *leg = stn->leg[d];
218            if (leg && !(leg->l.reverse & FLAG_REPLACEMENTLEG))
219               concatenate_trav(stn, d);
220         }
221      }
222   }
223}
224
225static void
226concatenate_trav(node *stn, int i)
227{
228   int j;
229   stack *trav;
230   node *stn2;
231   linkfor *newleg, *newleg2;
232
233   stn2 = stn->leg[i]->l.to;
234   /* Reject single legs as they may be already concatenated traverses */
235   if (fixed(stn2) || !two_node(stn2)) return;
236
237   trav = osnew(stack);
238   newleg2 = (linkfor*)osnew(linkrev);
239
240#if PRINT_NETBITS
241   printf("Concatenating trav "); print_prefix(stn->name); printf("<%p>",stn);
242#endif
243
244   newleg2->l.to = stn;
245   newleg2->l.reverse = i | FLAG_REPLACEMENTLEG;
246   trav->join1 = stn->leg[i];
247
248   j = reverse_leg_dirn(stn->leg[i]);
249   SVX_ASSERT(j == 0 || j == 1);
250
251   newleg = copy_link(stn->leg[i]);
252
253   while (1) {
254      stn = stn2;
255
256#if PRINT_NETBITS
257      printf(szLink); print_prefix(stn->name); printf("<%p>",stn);
258#endif
259
260      /* stop if fixed or 3 or 1 node */
261      if (fixed(stn) || !two_node(stn)) break;
262
263      remove_stn_from_list(&stnlist, stn);
264
265      i = j ^ 1; /* flip direction for other leg of 2 node */
266
267      stn2 = stn->leg[i]->l.to;
268      j = reverse_leg_dirn(stn->leg[i]);
269
270      addto_link(newleg, stn->leg[i]);
271   }
272
273   trav->join2 = stn->leg[j];
274   trav->next = ptr;
275   ptr = trav;
276
277   newleg->l.to = stn;
278   newleg->l.reverse = j | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
279
280   newleg2->l.to->leg[reverse_leg_dirn(newleg2)] = newleg;
281   /* i.e. stn->leg[i] = newleg; with original stn and i */
282
283   stn->leg[j] = newleg2;
284
285#if PRINT_NETBITS
286   putchar(' ');
287   print_var(&(newleg->v));
288   printf("\nStacked ");
289   print_prefix(newleg2->l.to->name);
290   printf(",%d-", reverse_leg_dirn(newleg2));
291   print_prefix(stn->name);
292   printf(",%d\n", j);
293#endif
294}
295
296#ifdef BLUNDER_DETECTION
297/* expected_error is actually squared... */
298/* only called if fhErrStat != NULL */
299static void
300do_gross(delta e, delta v, node *stn1, node *stn2, double expected_error)
301{
302   double hsqrd, rsqrd, s, cx, cy, cz;
303   double tot;
304   int i;
305   int output = 0;
306   prefix *name1 = stn1->name, *name2 = stn2->name;
307
308#if 0
309printf( "e = ( %.2f, %.2f, %.2f )", e[0], e[1], e[2] );
310printf( " v = ( %.2f, %.2f, %.2f )\n", v[0], v[1], v[2] );
311#endif
312   hsqrd = sqrd(v[0]) + sqrd(v[1]);
313   rsqrd = hsqrd + sqrd(v[2]);
314   if (rsqrd == 0.0) return;
315
316   cx = v[0] + e[0];
317   cy = v[1] + e[1];
318   cz = v[2] + e[2];
319
320   s = (e[0] * v[0] + e[1] * v[1] + e[2] * v[2]) / rsqrd;
321   tot = 0;
322   for (i = 2; i >= 0; i--) tot += sqrd(e[i] - v[i] * s);
323
324   if (tot <= expected_error) {
325      if (!output) {
326         fprint_prefix(fhErrStat, name1);
327         fputs("->", fhErrStat);
328         fprint_prefix(fhErrStat, name2);
329      }
330      fprintf(fhErrStat, " L: %.2f", sqrt(tot));
331      /* checked - works */
332      fprintf(fhErrStat, " (%.2fm -> %.2fm)", sqrt(sqrdd(v)), sqrt(sqrdd(v)) * (1 - s));
333      output = 1;
334   }
335
336   s = sqrd(cx) + sqrd(cy);
337   if (s > 0.0) {
338      s = hsqrd / s;
339      SVX_ASSERT(s >= 0.0);
340      s = sqrt(s);
341      s = 1 - s;
342      tot = sqrd(cx * s) + sqrd(cy * s) + sqrd(e[2]);
343      if (tot <= expected_error) {
344         double newval, oldval;
345         if (!output) {
346            fprint_prefix(fhErrStat, name1);
347            fputs("->", fhErrStat);
348            fprint_prefix(fhErrStat, name2);
349         }
350         fprintf(fhErrStat, " B: %.2f", sqrt(tot));
351         /* checked - works */
352         newval = deg(atan2(cx, cy));
353         if (newval < 0) newval += 360;
354         oldval = deg(atan2(v[0], v[1]));
355         if (oldval < 0) oldval += 360;
356         fprintf(fhErrStat, " (%.2fdeg -> %.2fdeg)", oldval, newval);
357         output = 1;
358      }
359   }
360
361   if (hsqrd > 0.0) {
362      double nx, ny;
363      s = (e[0] * v[1] - e[1] * v[0]) / hsqrd;
364      nx = cx - s * v[1];
365      ny = cy + s * v[0];
366      s = sqrd(nx) + sqrd(ny) + sqrd(cz);
367      if (s > 0.0) {
368         s = rsqrd / s;
369         SVX_ASSERT(s >= 0);
370         s = sqrt(s);
371         tot = sqrd(cx - s * nx) + sqrd(cy - s * ny) + sqrd(cz - s * cz);
372         if (tot <= expected_error) {
373            if (!output) {
374               fprint_prefix(fhErrStat, name1);
375               fputs("->", fhErrStat);
376               fprint_prefix(fhErrStat, name2);
377            }
378            fprintf(fhErrStat, " G: %.2f", sqrt(tot));
379            /* checked - works */
380            fprintf(fhErrStat, " (%.2fdeg -> %.2fdeg)",
381                    deg(atan2(v[2], sqrt(v[0] * v[0] + v[1] * v[1]))),
382                    deg(atan2(cz, sqrt(nx * nx + ny * ny))));
383            output = 1;
384         }
385      }
386   }
387   if (output) fputnl(fhErrStat);
388}
389#endif
390
391static void
392replace_travs(void)
393{
394   stack *ptrOld;
395   node *stn1, *stn2, *stn3;
396   int i, j, k;
397   double eTot = 0, lenTrav = 0, lenTot;
398   double eTotTheo = 0;
399   double vTot = 0, vTotTheo = 0, hTot = 0, hTotTheo = 0;
400   delta e, sc;
401   bool fEquate; /* used to indicate equates in output */
402   int cLegsTrav = 0;
403   bool fArtic;
404
405   out_current_action(msg(/*Calculating traverses between nodes*/127));
406
407   if (!fhErrStat && !fSuppress)
408      fhErrStat = safe_fopen_with_ext(fnm_output_base, EXT_SVX_ERRS, "w");
409
410   if (!pimg) {
411      char *fnm;
412#ifdef CHASM3DX
413      if (fUseNewFormat) {
414         fnm = add_ext(fnm_output_base, EXT_SVX_3DX);
415      } else {
416#endif
417         fnm = add_ext(fnm_output_base, EXT_SVX_3D);
418#ifdef CHASM3DX
419      }
420#endif
421      filename_register_output(fnm);
422
423#ifdef CHASM3DX
424      if (fUseNewFormat) {
425         pimg = cave_open_write(fnm, survey_title);
426         if (!pimg) fatalerror(cave_error(), fnm);
427      } else {
428#endif
429         img_output_version = 3;
430         pimg = img_open_write(fnm, survey_title, fTrue);
431         if (!pimg) fatalerror(img_error(), fnm);
432#ifdef CHASM3DX
433      }
434#endif
435      osfree(fnm);
436   }
437
438   /* First do all the one leg traverses */
439   FOR_EACH_STN(stn1, stnlist) {
440#if PRINT_NETBITS
441      printf("One leg traverses from ");
442      print_prefix(stn1->name);
443      printf(" [%p]\n", stn1);
444#endif
445      for (i = 0; i <= 2; i++) {
446         linkfor *leg = stn1->leg[i];
447         if (leg && data_here(leg) &&
448             !(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
449            SVX_ASSERT(fixed(stn1));
450            SVX_ASSERT(!fZeros(&leg->v));
451
452            stn2 = leg->l.to;
453            if (TSTBIT(leg->l.flags, FLAGS_SURFACE)) {
454               stn1->name->sflags |= BIT(SFLAGS_SURFACE);
455               stn2->name->sflags |= BIT(SFLAGS_SURFACE);
456            } else {
457               stn1->name->sflags |= BIT(SFLAGS_UNDERGROUND);
458               stn2->name->sflags |= BIT(SFLAGS_UNDERGROUND);
459            }
460#ifdef CHASM3DX
461            if (!fUseNewFormat) {
462#endif
463               img_write_item(pimg, img_MOVE, 0, NULL,
464                              POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
465               img_write_item(pimg, img_LINE, leg->l.flags,
466                              sprint_prefix(stn1->name->up),
467                              POS(stn2, 0), POS(stn2, 1), POS(stn2, 2));
468#ifdef CHASM3DX
469            }
470#endif
471            if (!(leg->l.reverse & FLAG_ARTICULATION)) {
472#ifdef BLUNDER_DETECTION
473               delta err;
474               int do_blunder;
475#else
476               if (fhErrStat) {
477                  fprint_prefix(fhErrStat, stn1->name);
478                  fputs(szLink, fhErrStat);
479                  fprint_prefix(fhErrStat, stn2->name);
480               }
481#endif
482               subdd(&e, &POSD(stn2), &POSD(stn1));
483               subdd(&e, &e, &leg->d);
484               if (fhErrStat) {
485                  eTot = sqrdd(e);
486                  hTot = sqrd(e[0]) + sqrd(e[1]);
487                  vTot = sqrd(e[2]);
488#ifndef NO_COVARIANCES
489                  /* FIXME: what about covariances? */
490                  hTotTheo = leg->v[0] + leg->v[1];
491                  vTotTheo = leg->v[2];
492                  eTotTheo = hTotTheo + vTotTheo;
493#else
494                  hTotTheo = leg->v[0] + leg->v[1];
495                  vTotTheo = leg->v[2];
496                  eTotTheo = hTotTheo + vTotTheo;
497#endif
498#ifdef BLUNDER_DETECTION
499                  memcpy(&err, &e, sizeof(delta));
500                  do_blunder = (eTot > eTotTheo);
501                  fputs("\ntraverse ", fhErrStat);
502                  fprint_prefix(fhErrStat, stn1->name);
503                  fputs("->", fhErrStat);
504                  fprint_prefix(fhErrStat, stn2->name);
505                  fprintf(fhErrStat, " e=(%.2f, %.2f, %.2f) mag=%.2f %s\n",
506                          e[0], e[1], e[2], sqrt(eTot),
507                          (do_blunder ? "suspect:" : "OK"));
508                  if (do_blunder)
509                     do_gross(err, leg->d, stn1, stn2, eTotTheo);
510#endif
511                  err_stat(1, sqrt(sqrdd(leg->d)), eTot, eTotTheo,
512                           hTot, hTotTheo, vTot, vTotTheo);
513               }
514            }
515         }
516      }
517   }
518
519   while (ptr != NULL) {
520      /* work out where traverse should be reconnected */
521      linkfor *leg = ptr->join1;
522      leg = reverse_leg(leg);
523      stn1 = leg->l.to;
524      i = reverse_leg_dirn(leg);
525
526      leg = ptr->join2;
527      leg = reverse_leg(leg);
528      stn2 = leg->l.to;
529      j = reverse_leg_dirn(leg);
530
531#if PRINT_NETBITS
532      printf(" Trav ");
533      print_prefix(stn1->name);
534      printf("<%p>[%d]%s...%s", stn1, i, szLink, szLink);
535      print_prefix(stn2->name);
536      printf("<%p>[%d]\n", stn2, j);
537#endif
538
539      SVX_ASSERT(fixed(stn1));
540      SVX_ASSERT(fixed(stn2));
541
542      /* calculate scaling factors for error distribution */
543      eTot = 0.0;
544      hTot = vTot = 0.0;
545      SVX_ASSERT(data_here(stn1->leg[i]));
546      if (fZeros(&stn1->leg[i]->v)) {
547         sc[0] = sc[1] = sc[2] = 0.0;
548      } else {
549         subdd(&e, &POSD(stn2), &POSD(stn1));
550         subdd(&e, &e, &stn1->leg[i]->d);
551         eTot = sqrdd(e);
552         hTot = sqrd(e[0]) + sqrd(e[1]);
553         vTot = sqrd(e[2]);
554         divds(&sc, &e, &stn1->leg[i]->v);
555      }
556#ifndef NO_COVARIANCES
557      /* FIXME: what about covariances? */
558      hTotTheo = stn1->leg[i]->v[0] + stn1->leg[i]->v[1];
559      vTotTheo = stn1->leg[i]->v[2];
560#else
561      hTotTheo = stn1->leg[i]->v[0] + stn1->leg[i]->v[1];
562      vTotTheo = stn1->leg[i]->v[2];
563#endif
564      eTotTheo = hTotTheo + vTotTheo;
565      cLegsTrav = 0;
566      lenTrav = 0.0;
567#ifdef CHASM3DX
568      if (!fUseNewFormat) {
569#endif
570         img_write_item(pimg, img_MOVE, 0, NULL,
571                        POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
572#ifdef CHASM3DX
573      }
574#endif
575
576      fArtic = stn1->leg[i]->l.reverse & FLAG_ARTICULATION;
577      osfree(stn1->leg[i]);
578      stn1->leg[i] = ptr->join1; /* put old link back in */
579
580      osfree(stn2->leg[j]);
581      stn2->leg[j] = ptr->join2; /* and the other end */
582
583#ifdef BLUNDER_DETECTION
584      delta err;
585      int do_blunder;
586      memcpy(&err, &e, sizeof(delta));
587      do_blunder = (eTot > eTotTheo);
588      if (fhErrStat && !fArtic) {
589         fputs("\ntraverse ", fhErrStat);
590         fprint_prefix(fhErrStat, stn1->name);
591         fputs("->", fhErrStat);
592         fprint_prefix(fhErrStat, stn2->name);
593         fprintf(fhErrStat, " e=(%.2f, %.2f, %.2f) mag=%.2f %s\n",
594                 e[0], e[1], e[2], sqrt(eTot),
595                 (do_blunder ? "suspect:" : "OK"));
596      }
597#endif
598      while (fTrue) {
599         int reached_end;
600         prefix *leg_pfx;
601
602         fEquate = fTrue;
603         /* get next node in traverse
604          * should have stn3->leg[k]->l.to == stn1 */
605         stn3 = stn1->leg[i]->l.to;
606         k = reverse_leg_dirn(stn1->leg[i]);
607         SVX_ASSERT2(stn3->leg[k]->l.to == stn1,
608                 "reverse leg doesn't reciprocate");
609
610         reached_end = (stn3 == stn2 && k == j);
611
612         if (data_here(stn1->leg[i])) {
613            leg_pfx = stn1->name->up;
614            leg = stn1->leg[i];
615#ifdef BLUNDER_DETECTION
616            if (do_blunder && fhErrStat)
617               do_gross(err, leg->d, stn1, stn3, eTotTheo);
618#endif
619            if (!reached_end)
620               adddd(&POSD(stn3), &POSD(stn1), &leg->d);
621         } else {
622            leg_pfx = stn3->name->up;
623            leg = stn3->leg[k];
624#ifdef BLUNDER_DETECTION
625            if (do_blunder && fhErrStat)
626               do_gross(err, leg->d, stn1, stn3, eTotTheo);
627#endif
628            if (!reached_end)
629               subdd(&POSD(stn3), &POSD(stn1), &leg->d);
630         }
631
632         lenTot = sqrdd(leg->d);
633
634         if (!fZeros(&leg->v)) fEquate = fFalse;
635         if (!reached_end) {
636            add_stn_to_list(&stnlist, stn3);
637            if (!fEquate) {
638               mulsd(&e, &leg->v, &sc);
639               adddd(&POSD(stn3), &POSD(stn3), &e);
640            }
641            fix(stn3);
642         }
643
644         if (!(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
645             if (TSTBIT(leg->l.flags, FLAGS_SURFACE)) {
646                stn1->name->sflags |= BIT(SFLAGS_SURFACE);
647                stn3->name->sflags |= BIT(SFLAGS_SURFACE);
648             } else {
649                stn1->name->sflags |= BIT(SFLAGS_UNDERGROUND);
650                stn3->name->sflags |= BIT(SFLAGS_UNDERGROUND);
651             }
652
653#ifdef CHASM3DX
654            if (!fUseNewFormat) {
655#endif
656               SVX_ASSERT(!fEquate);
657               SVX_ASSERT(!fZeros(&leg->v));
658               img_write_item(pimg, img_LINE, leg->l.flags,
659                              sprint_prefix(leg_pfx),
660                              POS(stn3, 0), POS(stn3, 1), POS(stn3, 2));
661#ifdef CHASM3DX
662            }
663#endif
664         }
665
666         /* FIXME: equate at the start of a traverse treated specially
667          * - what about equates at end? */
668         if (stn1->name != stn3->name && !(fEquate && cLegsTrav == 0)) {
669            /* (node not part of same stn) &&
670             * (not equate at start of traverse) */
671#ifndef BLUNDER_DETECTION
672            if (fhErrStat && !fArtic) {
673               if (!stn1->name->ident) {
674                  /* FIXME: not ideal */
675                  fputs("<fixed point>", fhErrStat);
676               } else {
677                  fprint_prefix(fhErrStat, stn1->name);
678               }
679               fputs(fEquate ? szLinkEq : szLink, fhErrStat);
680               if (reached_end) {
681                  if (!stn3->name->ident) {
682                     /* FIXME: not ideal */
683                     fputs("<fixed point>", fhErrStat);
684                  } else {
685                     fprint_prefix(fhErrStat, stn3->name);
686                  }
687               }
688            }
689#endif
690            if (!fEquate) {
691               cLegsTrav++;
692               lenTrav += sqrt(lenTot);
693            }
694         } else {
695#if SHOW_INTERNAL_LEGS
696            if (fhErrStat && !fArtic) fprintf(fhErrStat, "+");
697#endif
698            if (lenTot > 0.0) {
699#if DEBUG_INVALID
700               fprintf(stderr, "lenTot = %8.4f ", lenTot);
701               fprint_prefix(stderr, stn1->name);
702               fprintf(stderr, " -> ");
703               fprint_prefix(stderr, stn3->name);
704#endif
705               BUG("during calculation of closure errors");
706            }
707         }
708         if (reached_end) break;
709
710         i = k ^ 1; /* flip direction for other leg of 2 node */
711
712         stn1 = stn3;
713      } /* endwhile */
714
715      if (cLegsTrav && !fArtic && fhErrStat)
716         err_stat(cLegsTrav, lenTrav, eTot, eTotTheo,
717                  hTot, hTotTheo, vTot, vTotTheo);
718
719      ptrOld = ptr;
720      ptr = ptr->next;
721      osfree(ptrOld);
722   }
723
724   /* Leave fhErrStat open in case we're asked to close loops again... */
725}
726
727static void
728err_stat(int cLegsTrav, double lenTrav,
729         double eTot, double eTotTheo,
730         double hTot, double hTotTheo,
731         double vTot, double vTotTheo)
732{
733   double sqrt_eTot;
734   if (!fSuppress) {
735      fputnl(fhErrStat);
736      sqrt_eTot = sqrt(eTot);
737      fprintf(fhErrStat, msg(/*Original length%7.2fm (%3d legs), moved%7.2fm (%5.2fm/leg). */145),
738              lenTrav, cLegsTrav, sqrt_eTot, sqrt_eTot / cLegsTrav);
739      if (lenTrav > 0.0)
740         fprintf(fhErrStat, msg(/*Error%7.2f%%*/146), 100 * sqrt_eTot / lenTrav);
741      else
742         fputs(msg(/*Error    N/A*/147), fhErrStat);
743      fputnl(fhErrStat);
744      fprintf(fhErrStat, "%f\n", sqrt(eTot / eTotTheo));
745      fprintf(fhErrStat, "H: %f V: %f\n",
746              sqrt(hTot / hTotTheo), sqrt(vTot / vTotTheo));
747      fputnl(fhErrStat);
748   }
749}
750
751static void
752replace_trailing_travs(void)
753{
754   stackTrail *ptrOld;
755   node *stn1, *stn2;
756   linkfor *leg;
757   int i;
758
759   out_current_action(msg(/*Calculating trailing traverses*/128));
760
761   while (ptrTrail != NULL) {
762      leg = ptrTrail->join1;
763      leg = reverse_leg(leg);
764      stn1 = leg->l.to;
765      i = reverse_leg_dirn(leg);
766#if PRINT_NETBITS
767      printf(" Trailing trav ");
768      print_prefix(stn1->name);
769      printf("<%p>", stn1);
770      printf("%s...\n", szLink);
771      printf("    attachment stn is at (%f, %f, %f)\n",
772             POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
773#endif
774      /* We may have swapped the links round when we removed the leg.  If
775       * we did then stn1->leg[i] will be in use.  The link we swapped
776       * with is the first free leg */
777      if (stn1->leg[i]) {
778         /* j is the direction to swap with */
779         int j = (stn1->leg[1]) ? 2 : 1;
780         /* change the other direction of leg i to use leg j */
781         reverse_leg(stn1->leg[i])->l.reverse += j - i;
782         stn1->leg[j] = stn1->leg[i];
783      }
784      stn1->leg[i] = ptrTrail->join1;
785      SVX_ASSERT(fixed(stn1));
786#ifdef CHASM3DX
787      if (!fUseNewFormat) {
788#endif
789         img_write_item(pimg, img_MOVE, 0, NULL,
790                        POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
791#ifdef CHASM3DX
792      }
793#endif
794
795      while (1) {
796         prefix *leg_pfx;
797         int j;
798
799         leg = stn1->leg[i];
800         stn2 = leg->l.to;
801         j = reverse_leg_dirn(leg);
802         if (data_here(leg)) {
803            leg_pfx = stn1->name->up;
804            adddd(&POSD(stn2), &POSD(stn1), &leg->d);
805#if 0
806            printf("Adding leg (%f, %f, %f)\n", leg->d[0], leg->d[1], leg->d[2]);
807#endif
808         } else {
809            leg_pfx = stn2->name->up;
810            leg = stn2->leg[j];
811            subdd(&POSD(stn2), &POSD(stn1), &leg->d);
812#if 0
813            printf("Subtracting reverse leg (%f, %f, %f)\n", leg->d[0], leg->d[1], leg->d[2]);
814#endif
815         }
816
817         fix(stn2);
818         add_stn_to_list(&stnlist, stn2);
819         if (!(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
820             if (TSTBIT(leg->l.flags, FLAGS_SURFACE)) {
821                stn1->name->sflags |= BIT(SFLAGS_SURFACE);
822                stn2->name->sflags |= BIT(SFLAGS_SURFACE);
823             } else {
824                stn1->name->sflags |= BIT(SFLAGS_UNDERGROUND);
825                stn2->name->sflags |= BIT(SFLAGS_UNDERGROUND);
826             }
827         }
828#ifdef CHASM3DX
829         if (!fUseNewFormat) {
830#endif
831            if (!(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
832               SVX_ASSERT(!fZeros(&leg->v));
833               img_write_item(pimg, img_LINE, leg->l.flags,
834                              sprint_prefix(leg_pfx),
835                              POS(stn2, 0), POS(stn2, 1), POS(stn2, 2));
836            }
837#ifdef CHASM3DX
838         }
839#endif
840
841         /* stop if not 2 node */
842         if (!two_node(stn2)) break;
843
844         stn1 = stn2;
845         i = j ^ 1; /* flip direction for other leg of 2 node */
846      }
847
848      ptrOld = ptrTrail;
849      ptrTrail = ptrTrail->next;
850      osfree(ptrOld);
851   }
852
853   /* write out connections with no survey data */
854#ifdef CHASM3DX
855   if (!fUseNewFormat) {
856#endif
857      while (nosurveyhead) {
858         nosurveylink *p = nosurveyhead;
859         SVX_ASSERT(fixed(p->fr));
860         SVX_ASSERT(fixed(p->to));
861         if (TSTBIT(p->flags, FLAGS_SURFACE)) {
862            p->fr->name->sflags |= BIT(SFLAGS_SURFACE);
863            p->to->name->sflags |= BIT(SFLAGS_SURFACE);
864         } else {
865            p->fr->name->sflags |= BIT(SFLAGS_UNDERGROUND);
866            p->to->name->sflags |= BIT(SFLAGS_UNDERGROUND);
867         }
868         img_write_item(pimg, img_MOVE, 0, NULL,
869                        POS(p->fr, 0), POS(p->fr, 1), POS(p->fr, 2));
870         img_write_item(pimg, img_LINE, p->flags,
871                        sprint_prefix(p->fr->name->up),
872                        POS(p->to, 0), POS(p->to, 1), POS(p->to, 2));
873         nosurveyhead = p->next;
874         osfree(p);
875      }
876#ifdef CHASM3DX
877   }
878#endif
879
880   /* write stations to .3d file and free legs and stations */
881   FOR_EACH_STN(stn1, stnlist) {
882      int d;
883      SVX_ASSERT(fixed(stn1));
884      /* take care of unused fixed points */
885#ifdef CHASM3DX
886      if (!fUseNewFormat) {
887#endif
888         if (stn1->name->stn == stn1 && stn1->name->ident) {
889            int sf = stn1->name->sflags;
890            if (!TSTBIT(sf, SFLAGS_SOLVED)) {
891               /* Set flag to stop station being rewritten after *solve */
892               stn1->name->sflags = sf | BIT(SFLAGS_SOLVED);
893               sf &= SFLAGS_MASK;
894               if (stn1->name->max_export) sf |= BIT(SFLAGS_EXPORTED);
895               img_write_item(pimg, img_LABEL, sf, sprint_prefix(stn1->name),
896                              POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
897            }
898         }
899#ifdef CHASM3DX
900      }
901#endif
902      /* update coords of bounding box, ignoring the base positions
903       * of points fixed with error estimates and only counting stations
904       * in underground surveys. */
905      if (stn1->name->ident && TSTBIT(stn1->name->sflags, SFLAGS_UNDERGROUND)) {
906         for (d = 0; d < 3; d++) {
907            if (POS(stn1, d) < min[d]) {
908               min[d] = POS(stn1, d);
909               pfxLo[d] = stn1->name;
910            }
911            if (POS(stn1, d) > max[d]) {
912               max[d] = POS(stn1, d);
913               pfxHi[d] = stn1->name;
914            }
915         }
916      }
917
918      d = stn1->name->shape;
919      if (d < 0) {
920         /* "*fix STN reference ..." sets order negative to suppress the
921          * unused fixed point warning */
922         stn1->name->shape = -1 - d;
923      } else if (d <= 1) {
924         if (d == 0 ||
925             (stn1->leg[0] && !stn1->leg[0]->l.to->name->ident)) {
926            /* Unused fixed points without and with error estimates */
927            warning_in_file(stn1->name->filename, stn1->name->line,
928                    /*Unused fixed point `%s'*/73, sprint_prefix(stn1->name));
929         }
930      }
931
932      /* For stations fixed with error estimates, we need to ignore the leg to
933       * the "real" fixed point in the node stats.
934       */
935      if (stn1->leg[0] && !stn1->leg[0]->l.to->name->ident)
936         stn1->name->shape--;
937
938      for (i = 0; i <= 2; i++) {
939         leg = stn1->leg[i];
940         /* only want to think about forwards legs */
941         if (leg && data_here(leg)) {
942            linkfor *legRev;
943            node *stnB;
944            int iB;
945            stnB = leg->l.to;
946            iB = reverse_leg_dirn(leg);
947            legRev = stnB->leg[iB];
948            SVX_ASSERT2(legRev->l.to == stn1, "leg doesn't reciprocate");
949            SVX_ASSERT(fixed(stn1));
950            if (!(leg->l.flags &
951                  (BIT(FLAGS_DUPLICATE)|BIT(FLAGS_SPLAY)|
952                   BIT(FLAGS_SURFACE)))) {
953               /* check not an equating leg, or one inside an sdfix point */
954               if (!(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
955                  totadj += sqrt(sqrd(POS(stnB, 0) - POS(stn1, 0)) +
956                                 sqrd(POS(stnB, 1) - POS(stn1, 1)) +
957                                 sqrd(POS(stnB, 2) - POS(stn1, 2)));
958                  total += sqrt(sqrdd(leg->d));
959                  totplan += hypot(leg->d[0], leg->d[1]);
960                  totvert += fabs(leg->d[2]);
961               }
962            }
963            osfree(leg);
964            osfree(legRev);
965            stn1->leg[i] = stnB->leg[iB] = NULL;
966         }
967      }
968   }
969
970   /* The station position is attached to the name, so we leave the names and
971    * positions in place - they can then be picked up if we have a *solve
972    * followed by more data */
973   for (stn1 = stnlist; stn1; stn1 = stn2) {
974      stn2 = stn1->next;
975      stn1->name->stn = NULL;
976      osfree(stn1);
977   }
978   stnlist = NULL;
979}
Note: See TracBrowser for help on using the repository browser.