source: git/trunk/src/netskel.c @ 7bb8184

Last change on this file since 7bb8184 was 7bb8184, checked in by Olly Betts <olly@…>, 13 years ago

Retagging 1.2.0

git-svn-id: file:///home/survex-svn/survex/tags/1.2.0@3664 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,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);
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->days1 = leg->meta->days1;
448                pimg->days2 = leg->meta->days2;
449            } else {
450                pimg->days1 = pimg->days2 = -1;
451            }
452            img_write_item(pimg, img_LINE, leg->l.flags,
453                           sprint_prefix(stn1->name->up),
454                           POS(stn2, 0), POS(stn2, 1), POS(stn2, 2));
455            if (!(leg->l.reverse & FLAG_ARTICULATION)) {
456#ifdef BLUNDER_DETECTION
457               delta err;
458               int do_blunder;
459#else
460               if (fhErrStat) {
461                  fprint_prefix(fhErrStat, stn1->name);
462                  fputs(szLink, fhErrStat);
463                  fprint_prefix(fhErrStat, stn2->name);
464               }
465#endif
466               subdd(&e, &POSD(stn2), &POSD(stn1));
467               subdd(&e, &e, &leg->d);
468               if (fhErrStat) {
469                  eTot = sqrdd(e);
470                  hTot = sqrd(e[0]) + sqrd(e[1]);
471                  vTot = sqrd(e[2]);
472#ifndef NO_COVARIANCES
473                  /* FIXME: what about covariances? */
474                  hTotTheo = leg->v[0] + leg->v[1];
475                  vTotTheo = leg->v[2];
476                  eTotTheo = hTotTheo + vTotTheo;
477#else
478                  hTotTheo = leg->v[0] + leg->v[1];
479                  vTotTheo = leg->v[2];
480                  eTotTheo = hTotTheo + vTotTheo;
481#endif
482#ifdef BLUNDER_DETECTION
483                  memcpy(&err, &e, sizeof(delta));
484                  do_blunder = (eTot > eTotTheo);
485                  fputs("\ntraverse ", fhErrStat);
486                  fprint_prefix(fhErrStat, stn1->name);
487                  fputs("->", fhErrStat);
488                  fprint_prefix(fhErrStat, stn2->name);
489                  fprintf(fhErrStat, " e=(%.2f, %.2f, %.2f) mag=%.2f %s\n",
490                          e[0], e[1], e[2], sqrt(eTot),
491                          (do_blunder ? "suspect:" : "OK"));
492                  if (do_blunder)
493                     do_gross(err, leg->d, stn1, stn2, eTotTheo);
494#endif
495                  err_stat(1, sqrt(sqrdd(leg->d)), eTot, eTotTheo,
496                           hTot, hTotTheo, vTot, vTotTheo);
497               }
498            }
499         }
500      }
501   }
502
503   while (ptr != NULL) {
504      /* work out where traverse should be reconnected */
505      linkfor *leg = ptr->join1;
506      leg = reverse_leg(leg);
507      stn1 = leg->l.to;
508      i = reverse_leg_dirn(leg);
509
510      leg = ptr->join2;
511      leg = reverse_leg(leg);
512      stn2 = leg->l.to;
513      j = reverse_leg_dirn(leg);
514
515#if PRINT_NETBITS
516      printf(" Trav ");
517      print_prefix(stn1->name);
518      printf("<%p>[%d]%s...%s", stn1, i, szLink, szLink);
519      print_prefix(stn2->name);
520      printf("<%p>[%d]\n", stn2, j);
521#endif
522
523      SVX_ASSERT(fixed(stn1));
524      SVX_ASSERT(fixed(stn2));
525
526      /* calculate scaling factors for error distribution */
527      eTot = 0.0;
528      hTot = vTot = 0.0;
529      SVX_ASSERT(data_here(stn1->leg[i]));
530      if (fZeros(&stn1->leg[i]->v)) {
531         sc[0] = sc[1] = sc[2] = 0.0;
532      } else {
533         subdd(&e, &POSD(stn2), &POSD(stn1));
534         subdd(&e, &e, &stn1->leg[i]->d);
535         eTot = sqrdd(e);
536         hTot = sqrd(e[0]) + sqrd(e[1]);
537         vTot = sqrd(e[2]);
538         divds(&sc, &e, &stn1->leg[i]->v);
539      }
540#ifndef NO_COVARIANCES
541      /* FIXME: what about covariances? */
542      hTotTheo = stn1->leg[i]->v[0] + stn1->leg[i]->v[1];
543      vTotTheo = stn1->leg[i]->v[2];
544#else
545      hTotTheo = stn1->leg[i]->v[0] + stn1->leg[i]->v[1];
546      vTotTheo = stn1->leg[i]->v[2];
547#endif
548      eTotTheo = hTotTheo + vTotTheo;
549      cLegsTrav = 0;
550      lenTrav = 0.0;
551      img_write_item(pimg, img_MOVE, 0, NULL,
552                     POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
553
554      fArtic = stn1->leg[i]->l.reverse & FLAG_ARTICULATION;
555      osfree(stn1->leg[i]);
556      stn1->leg[i] = ptr->join1; /* put old link back in */
557
558      osfree(stn2->leg[j]);
559      stn2->leg[j] = ptr->join2; /* and the other end */
560
561#ifdef BLUNDER_DETECTION
562      delta err;
563      int do_blunder;
564      memcpy(&err, &e, sizeof(delta));
565      do_blunder = (eTot > eTotTheo);
566      if (fhErrStat && !fArtic) {
567         fputs("\ntraverse ", fhErrStat);
568         fprint_prefix(fhErrStat, stn1->name);
569         fputs("->", fhErrStat);
570         fprint_prefix(fhErrStat, stn2->name);
571         fprintf(fhErrStat, " e=(%.2f, %.2f, %.2f) mag=%.2f %s\n",
572                 e[0], e[1], e[2], sqrt(eTot),
573                 (do_blunder ? "suspect:" : "OK"));
574      }
575#endif
576      while (fTrue) {
577         int reached_end;
578         prefix *leg_pfx;
579
580         fEquate = fTrue;
581         /* get next node in traverse
582          * should have stn3->leg[k]->l.to == stn1 */
583         stn3 = stn1->leg[i]->l.to;
584         k = reverse_leg_dirn(stn1->leg[i]);
585         SVX_ASSERT2(stn3->leg[k]->l.to == stn1,
586                 "reverse leg doesn't reciprocate");
587
588         reached_end = (stn3 == stn2 && k == j);
589
590         if (data_here(stn1->leg[i])) {
591            leg_pfx = stn1->name->up;
592            leg = stn1->leg[i];
593#ifdef BLUNDER_DETECTION
594            if (do_blunder && fhErrStat)
595               do_gross(err, leg->d, stn1, stn3, eTotTheo);
596#endif
597            if (!reached_end)
598               adddd(&POSD(stn3), &POSD(stn1), &leg->d);
599         } else {
600            leg_pfx = stn3->name->up;
601            leg = stn3->leg[k];
602#ifdef BLUNDER_DETECTION
603            if (do_blunder && fhErrStat)
604               do_gross(err, leg->d, stn1, stn3, eTotTheo);
605#endif
606            if (!reached_end)
607               subdd(&POSD(stn3), &POSD(stn1), &leg->d);
608         }
609
610         lenTot = sqrdd(leg->d);
611
612         if (!fZeros(&leg->v)) fEquate = fFalse;
613         if (!reached_end) {
614            add_stn_to_list(&stnlist, stn3);
615            if (!fEquate) {
616               mulsd(&e, &leg->v, &sc);
617               adddd(&POSD(stn3), &POSD(stn3), &e);
618            }
619            fix(stn3);
620         }
621
622         if (!(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
623             if (TSTBIT(leg->l.flags, FLAGS_SURFACE)) {
624                stn1->name->sflags |= BIT(SFLAGS_SURFACE);
625                stn3->name->sflags |= BIT(SFLAGS_SURFACE);
626             } else {
627                stn1->name->sflags |= BIT(SFLAGS_UNDERGROUND);
628                stn3->name->sflags |= BIT(SFLAGS_UNDERGROUND);
629             }
630
631            SVX_ASSERT(!fEquate);
632            SVX_ASSERT(!fZeros(&leg->v));
633            if (leg->meta) {
634                pimg->days1 = leg->meta->days1;
635                pimg->days2 = leg->meta->days2;
636            } else {
637                pimg->days1 = pimg->days2 = -1;
638            }
639            img_write_item(pimg, img_LINE, leg->l.flags,
640                           sprint_prefix(leg_pfx),
641                           POS(stn3, 0), POS(stn3, 1), POS(stn3, 2));
642         }
643
644         /* FIXME: equate at the start of a traverse treated specially
645          * - what about equates at end? */
646         if (stn1->name != stn3->name && !(fEquate && cLegsTrav == 0)) {
647            /* (node not part of same stn) &&
648             * (not equate at start of traverse) */
649#ifndef BLUNDER_DETECTION
650            if (fhErrStat && !fArtic) {
651               if (!stn1->name->ident) {
652                  /* FIXME: not ideal */
653                  fputs("<fixed point>", fhErrStat);
654               } else {
655                  fprint_prefix(fhErrStat, stn1->name);
656               }
657               fputs(fEquate ? szLinkEq : szLink, fhErrStat);
658               if (reached_end) {
659                  if (!stn3->name->ident) {
660                     /* FIXME: not ideal */
661                     fputs("<fixed point>", fhErrStat);
662                  } else {
663                     fprint_prefix(fhErrStat, stn3->name);
664                  }
665               }
666            }
667#endif
668            if (!fEquate) {
669               cLegsTrav++;
670               lenTrav += sqrt(lenTot);
671            }
672         } else {
673#if SHOW_INTERNAL_LEGS
674            if (fhErrStat && !fArtic) fprintf(fhErrStat, "+");
675#endif
676            if (lenTot > 0.0) {
677#if DEBUG_INVALID
678               fprintf(stderr, "lenTot = %8.4f ", lenTot);
679               fprint_prefix(stderr, stn1->name);
680               fprintf(stderr, " -> ");
681               fprint_prefix(stderr, stn3->name);
682#endif
683               BUG("during calculation of closure errors");
684            }
685         }
686         if (reached_end) break;
687
688         i = k ^ 1; /* flip direction for other leg of 2 node */
689
690         stn1 = stn3;
691      } /* endwhile */
692
693      if (cLegsTrav && !fArtic && fhErrStat)
694         err_stat(cLegsTrav, lenTrav, eTot, eTotTheo,
695                  hTot, hTotTheo, vTot, vTotTheo);
696
697      ptrOld = ptr;
698      ptr = ptr->next;
699      osfree(ptrOld);
700   }
701
702   /* Leave fhErrStat open in case we're asked to close loops again... */
703}
704
705static void
706err_stat(int cLegsTrav, double lenTrav,
707         double eTot, double eTotTheo,
708         double hTot, double hTotTheo,
709         double vTot, double vTotTheo)
710{
711   double E = sqrt(eTot / eTotTheo);
712   double H = sqrt(hTot / hTotTheo);
713   double V = sqrt(vTot / vTotTheo);
714   if (!fSuppress) {
715      double sqrt_eTot = sqrt(eTot);
716      fputnl(fhErrStat);
717      fprintf(fhErrStat, msg(/*Original length%7.2fm (%3d legs), moved%7.2fm (%5.2fm/leg). */145),
718              lenTrav, cLegsTrav, sqrt_eTot, sqrt_eTot / cLegsTrav);
719      if (lenTrav > 0.0)
720         fprintf(fhErrStat, msg(/*Error%7.2f%%*/146), 100 * sqrt_eTot / lenTrav);
721      else
722         fputs(msg(/*Error    N/A*/147), fhErrStat);
723      fputnl(fhErrStat);
724      fprintf(fhErrStat, "%f\n", E);
725      fprintf(fhErrStat, "H: %f V: %f\n", H, V);
726      fputnl(fhErrStat);
727   }
728   img_write_errors(pimg, cLegsTrav, lenTrav, E, H, V);
729}
730
731static void
732replace_trailing_travs(void)
733{
734   stackTrail *ptrOld;
735   node *stn1, *stn2;
736   linkfor *leg;
737   int i;
738
739   out_current_action(msg(/*Calculating trailing traverses*/128));
740
741   while (ptrTrail != NULL) {
742      leg = ptrTrail->join1;
743      leg = reverse_leg(leg);
744      stn1 = leg->l.to;
745      i = reverse_leg_dirn(leg);
746#if PRINT_NETBITS
747      printf(" Trailing trav ");
748      print_prefix(stn1->name);
749      printf("<%p>", stn1);
750      printf("%s...\n", szLink);
751      printf("    attachment stn is at (%f, %f, %f)\n",
752             POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
753#endif
754      /* We may have swapped the links round when we removed the leg.  If
755       * we did then stn1->leg[i] will be in use.  The link we swapped
756       * with is the first free leg */
757      if (stn1->leg[i]) {
758         /* j is the direction to swap with */
759         int j = (stn1->leg[1]) ? 2 : 1;
760         /* change the other direction of leg i to use leg j */
761         reverse_leg(stn1->leg[i])->l.reverse += j - i;
762         stn1->leg[j] = stn1->leg[i];
763      }
764      stn1->leg[i] = ptrTrail->join1;
765      SVX_ASSERT(fixed(stn1));
766      img_write_item(pimg, img_MOVE, 0, NULL,
767                     POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
768
769      while (1) {
770         prefix *leg_pfx;
771         int j;
772
773         leg = stn1->leg[i];
774         stn2 = leg->l.to;
775         j = reverse_leg_dirn(leg);
776         if (data_here(leg)) {
777            leg_pfx = stn1->name->up;
778            adddd(&POSD(stn2), &POSD(stn1), &leg->d);
779#if 0
780            printf("Adding leg (%f, %f, %f)\n", leg->d[0], leg->d[1], leg->d[2]);
781#endif
782         } else {
783            leg_pfx = stn2->name->up;
784            leg = stn2->leg[j];
785            subdd(&POSD(stn2), &POSD(stn1), &leg->d);
786#if 0
787            printf("Subtracting reverse leg (%f, %f, %f)\n", leg->d[0], leg->d[1], leg->d[2]);
788#endif
789         }
790
791         fix(stn2);
792         add_stn_to_list(&stnlist, stn2);
793         if (!(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
794             if (TSTBIT(leg->l.flags, FLAGS_SURFACE)) {
795                stn1->name->sflags |= BIT(SFLAGS_SURFACE);
796                stn2->name->sflags |= BIT(SFLAGS_SURFACE);
797             } else {
798                stn1->name->sflags |= BIT(SFLAGS_UNDERGROUND);
799                stn2->name->sflags |= BIT(SFLAGS_UNDERGROUND);
800             }
801         }
802         if (!(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
803            SVX_ASSERT(!fZeros(&leg->v));
804            if (leg->meta) {
805                pimg->days1 = leg->meta->days1;
806                pimg->days2 = leg->meta->days2;
807            } else {
808                pimg->days1 = pimg->days2 = -1;
809            }
810            img_write_item(pimg, img_LINE, leg->l.flags,
811                           sprint_prefix(leg_pfx),
812                           POS(stn2, 0), POS(stn2, 1), POS(stn2, 2));
813         }
814
815         /* stop if not 2 node */
816         if (!two_node(stn2)) break;
817
818         stn1 = stn2;
819         i = j ^ 1; /* flip direction for other leg of 2 node */
820      }
821
822      ptrOld = ptrTrail;
823      ptrTrail = ptrTrail->next;
824      osfree(ptrOld);
825   }
826
827   /* write out connections with no survey data */
828   while (nosurveyhead) {
829      nosurveylink *p = nosurveyhead;
830      SVX_ASSERT(fixed(p->fr));
831      SVX_ASSERT(fixed(p->to));
832      if (TSTBIT(p->flags, FLAGS_SURFACE)) {
833         p->fr->name->sflags |= BIT(SFLAGS_SURFACE);
834         p->to->name->sflags |= BIT(SFLAGS_SURFACE);
835      } else {
836         p->fr->name->sflags |= BIT(SFLAGS_UNDERGROUND);
837         p->to->name->sflags |= BIT(SFLAGS_UNDERGROUND);
838      }
839      img_write_item(pimg, img_MOVE, 0, NULL,
840                     POS(p->fr, 0), POS(p->fr, 1), POS(p->fr, 2));
841      if (p->meta) {
842          pimg->days1 = p->meta->days1;
843          pimg->days2 = p->meta->days2;
844      } else {
845          pimg->days1 = pimg->days2 = -1;
846      }
847      img_write_item(pimg, img_LINE, p->flags,
848                     sprint_prefix(p->fr->name->up),
849                     POS(p->to, 0), POS(p->to, 1), POS(p->to, 2));
850      nosurveyhead = p->next;
851      osfree(p);
852   }
853
854   /* write stations to .3d file and free legs and stations */
855   FOR_EACH_STN(stn1, stnlist) {
856      int d;
857      SVX_ASSERT(fixed(stn1));
858      /* take care of unused fixed points */
859      if (stn1->name->stn == stn1 && stn1->name->ident) {
860         int sf = stn1->name->sflags;
861         if (!TSTBIT(sf, SFLAGS_SOLVED)) {
862            /* Set flag to stop station being rewritten after *solve. */
863            stn1->name->sflags = sf | BIT(SFLAGS_SOLVED);
864            sf &= SFLAGS_MASK;
865            if (stn1->name->max_export) sf |= BIT(SFLAGS_EXPORTED);
866            img_write_item(pimg, img_LABEL, sf, sprint_prefix(stn1->name),
867                           POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
868         }
869      }
870      /* update coords of bounding box, ignoring the base positions
871       * of points fixed with error estimates and only counting stations
872       * in underground surveys. */
873      if (stn1->name->ident && TSTBIT(stn1->name->sflags, SFLAGS_UNDERGROUND)) {
874         for (d = 0; d < 3; d++) {
875            if (POS(stn1, d) < min[d]) {
876               min[d] = POS(stn1, d);
877               pfxLo[d] = stn1->name;
878            }
879            if (POS(stn1, d) > max[d]) {
880               max[d] = POS(stn1, d);
881               pfxHi[d] = stn1->name;
882            }
883         }
884      }
885
886      d = stn1->name->shape;
887      if (d < 0) {
888         /* "*fix STN reference ..." sets order negative to suppress the
889          * unused fixed point warning */
890         stn1->name->shape = -1 - d;
891      } else if (d <= 1) {
892         if (d == 0 ||
893             (stn1->leg[0] && !stn1->leg[0]->l.to->name->ident)) {
894            /* Unused fixed points without and with error estimates */
895            warning_in_file(stn1->name->filename, stn1->name->line,
896                    /*Unused fixed point `%s'*/73, sprint_prefix(stn1->name));
897         }
898      }
899
900      /* For stations fixed with error estimates, we need to ignore the leg to
901       * the "real" fixed point in the node stats.
902       */
903      if (stn1->leg[0] && !stn1->leg[0]->l.to->name->ident)
904         stn1->name->shape--;
905
906      for (i = 0; i <= 2; i++) {
907         leg = stn1->leg[i];
908         /* only want to think about forwards legs */
909         if (leg && data_here(leg)) {
910            linkfor *legRev;
911            node *stnB;
912            int iB;
913            stnB = leg->l.to;
914            iB = reverse_leg_dirn(leg);
915            legRev = stnB->leg[iB];
916            SVX_ASSERT2(legRev->l.to == stn1, "leg doesn't reciprocate");
917            SVX_ASSERT(fixed(stn1));
918            if (!(leg->l.flags &
919                  (BIT(FLAGS_DUPLICATE)|BIT(FLAGS_SPLAY)|
920                   BIT(FLAGS_SURFACE)))) {
921               /* check not an equating leg, or one inside an sdfix point */
922               if (!(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
923                  totadj += sqrt(sqrd(POS(stnB, 0) - POS(stn1, 0)) +
924                                 sqrd(POS(stnB, 1) - POS(stn1, 1)) +
925                                 sqrd(POS(stnB, 2) - POS(stn1, 2)));
926                  total += sqrt(sqrdd(leg->d));
927                  totplan += hypot(leg->d[0], leg->d[1]);
928                  totvert += fabs(leg->d[2]);
929               }
930            }
931            osfree(leg);
932            osfree(legRev);
933            stn1->leg[i] = stnB->leg[iB] = NULL;
934         }
935      }
936   }
937
938   /* The station position is attached to the name, so we leave the names and
939    * positions in place - they can then be picked up if we have a *solve
940    * followed by more data */
941   for (stn1 = stnlist; stn1; stn1 = stn2) {
942      stn2 = stn1->next;
943      stn1->name->stn = NULL;
944      osfree(stn1);
945   }
946   stnlist = NULL;
947}
948
949static void
950write_passage_models(void)
951{
952   lrudlist * psg = model;
953   while (psg) {
954      lrudlist * oldp;
955      lrud * xsect = psg->tube;
956      int xflags = 0;
957      while (xsect) {
958         lrud *oldx;
959         prefix *pfx;
960         const char *name;
961         pimg->l = xsect->l;
962         pimg->r = xsect->r;
963         pimg->u = xsect->u;
964         pimg->d = xsect->d;
965         if (xsect->meta) {
966             pimg->days1 = xsect->meta->days1;
967             pimg->days2 = xsect->meta->days2;
968         } else {
969             pimg->days1 = pimg->days2 = -1;
970         }
971
972         pfx = xsect->stn;
973         name = sprint_prefix(pfx);
974         oldx = xsect;
975         xsect = xsect->next;
976         osfree(oldx);
977
978         if (!pfx->pos) {
979             error_in_file(pfx->filename, pfx->line,
980                           /*Cross section specified at non-existent station `%s'*/83,
981                           name);
982         } else {
983             if (xsect == NULL) xflags = img_XFLAG_END;
984             img_write_item(pimg, img_XSECT, xflags, name, 0, 0, 0);
985         }
986      }
987      oldp = psg;
988      psg = psg->next;
989      osfree(oldp);
990   }
991   model = NULL;
992}
Note: See TracBrowser for help on using the repository browser.