source: git/src/netskel.c @ c61aa79

RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-data
Last change on this file since c61aa79 was c61aa79, checked in by Olly Betts <olly@…>, 18 years ago

Add "Colour by Error".

git-svn-id: file:///home/survex-svn/survex/branches/survex-1_1@3289 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

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