source: git/src/netskel.c @ c20d521

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

lib/,src/netskel.c,tests/: Drop "between nodes" from the progress
messages while solving the survey network, as the extra words don't
make the meaning clearer, and "node" doesn't mean exactly the same
here as the summary of nodes printed at the end of processing, which
is a bit confusing.

  • 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,2014 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*/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*/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.