source: git/src/netskel.c @ a405bc1

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

src/: IMG_HOSTED no longer affects the img API at all.

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