source: git/src/netskel.c @ c20d521

RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-datawalls-data-hanging-as-warning
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
RevLine 
[ff6cfe1]1/* netskel.c
[045c055]2 * Survex network reduction - remove trailing traverses and concatenate
3 * traverses between junctions
[c20d521]4 * Copyright (C) 1991-2004,2005,2006,2010,2011,2012,2013,2014 Olly Betts
[846746e]5 *
[89231c4]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.
[846746e]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
[89231c4]13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
[846746e]15 *
[89231c4]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
[d333899]18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
[045c055]19 */
20
[7fda0c8]21/* #define BLUNDER_DETECTION */
[045c055]22
23#if 0
24#define DEBUG_INVALID 1
25#define VALIDATE 1
[c30a8f3]26#define DUMP_NETWORK 1
[045c055]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"
[a405bc1]39#include "img_hosted.h"
[e329f0f]40#include "netartic.h"
[045c055]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));\
[421b7d2]64                                    fprintf((FH), " [%p]", (void*)(NAME)); )
[045c055]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);
[ee05463]74static void write_passage_models(void);
[045c055]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
[dfe4a520]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   }
[045c055]95   ptr = NULL;
96   ptrTrail = NULL;
97   dump_network();
98
[c30a8f3]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;
[cb3d1e2]105
[f5627353]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. */
[c30a8f3]112      node *stnFirst = NULL;
[cb3d1e2]113
[c30a8f3]114      /* New stations are pushed onto the head of the list, so the
[2140502]115       * first station added is the last in the list. */
[1fa9b83]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      }
[cb3d1e2]123
[1fa9b83]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!");
[4c07c51]127      SVX_ASSERT2(stnFirst, "no stations left in net!");
[c30a8f3]128      stn = stnFirst;
[ee7511a]129      printf(msg(/*Survey has no fixed points. Therefore I’ve fixed %s at (0,0,0)*/72),
[5b68ae1]130             sprint_prefix(stn->name));
131      putnl();
[c30a8f3]132      POS(stn,0) = (real)0.0;
133      POS(stn,1) = (real)0.0;
134      POS(stn,2) = (real)0.0;
135      fix(stn);
[045c055]136   }
137
[c30a8f3]138   first_solve = 0;
139
[045c055]140   remove_trailing_travs();
141   validate(); dump_network();
142   remove_travs();
143   validate(); dump_network();
144   remove_subnets();
145   validate(); dump_network();
[7222b04]146   articulate();
[045c055]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();
[ee05463]154
155   /* Now write out any passage models. */
156   write_passage_models();
[045c055]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
[e27a0c3]177            print_prefix(stn2->name); printf("<%p>",stn2); fputs(szLink, stdout);
[045c055]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));
[cb3d1e2]186
[045c055]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) */
[421b7d2]196         if ((j == 0 && !one_node(stn2)) || (j == 1 && three_node(stn2))) {
[045c055]197            /* i is the direction to swap with */
[eb18f4d]198            i = (three_node(stn2)) ? 2 : 1;
[045c055]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;
[c20d521]217   out_current_action(msg(/*Concatenating traverses*/126));
[045c055]218   FOR_EACH_STN(stn, stnlist) {
[4a0d231]219      if (fixed(stn) || three_node(stn)) {
[ec8a439]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         }
[045c055]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]);
[4c07c51]254   SVX_ASSERT(j == 0 || j == 1);
[045c055]255
256   newleg = copy_link(stn->leg[i]);
257
[cb3d1e2]258   while (1) {
[045c055]259      stn = stn2;
260
261#if PRINT_NETBITS
[e27a0c3]262      fputs(szLink, stdout); print_prefix(stn->name); printf("<%p>",stn);
[045c055]263#endif
[cb3d1e2]264
[045c055]265      /* stop if fixed or 3 or 1 node */
266      if (fixed(stn) || !two_node(stn)) break;
[cb3d1e2]267
[045c055]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   }
[cb3d1e2]277
[045c055]278   trav->join2 = stn->leg[j];
279   trav->next = ptr;
280   ptr = trav;
281
282   newleg->l.to = stn;
[4a0d231]283   newleg->l.reverse = j | FLAG_DATAHERE | FLAG_REPLACEMENTLEG;
[045c055]284
[ec8a439]285   newleg2->l.to->leg[reverse_leg_dirn(newleg2)] = newleg;
286   /* i.e. stn->leg[i] = newleg; with original stn and i */
287
[045c055]288   stn->leg[j] = newleg2;
289
290#if PRINT_NETBITS
291   putchar(' ');
[be97baf]292   print_var(&(newleg->v));
[045c055]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... */
[25ab06b]303/* only called if fhErrStat != NULL */
[045c055]304static void
[eb18f4d]305do_gross(delta e, delta v, node *stn1, node *stn2, double expected_error)
[cb3d1e2]306{
[045c055]307   double hsqrd, rsqrd, s, cx, cy, cz;
308   double tot;
309   int i;
310   int output = 0;
[647407d]311   prefix *name1 = stn1->name, *name2 = stn2->name;
[045c055]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
[25ab06b]329   if (tot <= expected_error) {
[045c055]330      if (!output) {
331         fprint_prefix(fhErrStat, name1);
332         fputs("->", fhErrStat);
333         fprint_prefix(fhErrStat, name2);
334      }
[647407d]335      fprintf(fhErrStat, " L: %.2f", sqrt(tot));
336      /* checked - works */
337      fprintf(fhErrStat, " (%.2fm -> %.2fm)", sqrt(sqrdd(v)), sqrt(sqrdd(v)) * (1 - s));
[045c055]338      output = 1;
339   }
340
341   s = sqrd(cx) + sqrd(cy);
342   if (s > 0.0) {
343      s = hsqrd / s;
[4c07c51]344      SVX_ASSERT(s >= 0.0);
[647407d]345      s = sqrt(s);
[045c055]346      s = 1 - s;
347      tot = sqrd(cx * s) + sqrd(cy * s) + sqrd(e[2]);
[25ab06b]348      if (tot <= expected_error) {
[647407d]349         double newval, oldval;
[045c055]350         if (!output) {
351            fprint_prefix(fhErrStat, name1);
352            fputs("->", fhErrStat);
353            fprint_prefix(fhErrStat, name2);
354         }
[647407d]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);
[045c055]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) {
[421b7d2]373         s = rsqrd / s;
[4c07c51]374         SVX_ASSERT(s >= 0);
[421b7d2]375         s = sqrt(s);
376         tot = sqrd(cx - s * nx) + sqrd(cy - s * ny) + sqrd(cz - s * cz);
[25ab06b]377         if (tot <= expected_error) {
[045c055]378            if (!output) {
379               fprint_prefix(fhErrStat, name1);
380               fputs("->", fhErrStat);
381               fprint_prefix(fhErrStat, name2);
382            }
[647407d]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))));
[045c055]388            output = 1;
389         }
390      }
391   }
[25ab06b]392   if (output) fputnl(fhErrStat);
[045c055]393}
394#endif
395
396static void
397replace_travs(void)
398{
399   stack *ptrOld;
400   node *stn1, *stn2, *stn3;
401   int i, j, k;
[407084d]402   double eTot = 0, lenTrav = 0, lenTot;
403   double eTotTheo = 0;
404   double vTot = 0, vTotTheo = 0, hTot = 0, hTotTheo = 0;
[eb18f4d]405   delta e, sc;
[045c055]406   bool fEquate; /* used to indicate equates in output */
[407084d]407   int cLegsTrav = 0;
[402c753]408   bool fArtic;
[045c055]409
[c20d521]410   out_current_action(msg(/*Calculating traverses*/127));
[045c055]411
[647407d]412   if (!fhErrStat && !fSuppress)
[045c055]413      fhErrStat = safe_fopen_with_ext(fnm_output_base, EXT_SVX_ERRS, "w");
414
[693388e]415   if (!pimg) {
[a4ae909]416      char *fnm = add_ext(fnm_output_base, EXT_SVX_3D);
[06a871f]417      filename_register_output(fnm);
[ce9057c]418      pimg = img_open_write(fnm, survey_title, 0);
[a4ae909]419      if (!pimg) fatalerror(img_error(), fnm);
[06a871f]420      osfree(fnm);
[045c055]421   }
422
423   /* First do all the one leg traverses */
424   FOR_EACH_STN(stn1, stnlist) {
[be97baf]425#if PRINT_NETBITS
426      printf("One leg traverses from ");
427      print_prefix(stn1->name);
428      printf(" [%p]\n", stn1);
429#endif
[045c055]430      for (i = 0; i <= 2; i++) {
431         linkfor *leg = stn1->leg[i];
432         if (leg && data_here(leg) &&
[693388e]433             !(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
[4c07c51]434            SVX_ASSERT(fixed(stn1));
435            SVX_ASSERT(!fZeros(&leg->v));
[693388e]436
[e6cfe52]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            }
[a4ae909]445            img_write_item(pimg, img_MOVE, 0, NULL,
446                           POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
447            if (leg->meta) {
[1ee204e]448                pimg->days1 = leg->meta->days1;
449                pimg->days2 = leg->meta->days2;
[a4ae909]450            } else {
[1ee204e]451                pimg->days1 = pimg->days2 = -1;
[e6cfe52]452            }
[eb5aea0]453            pimg->style = (leg->l.flags >> FLAGS_STYLE_BIT0) & 0x07;
454            img_write_item(pimg, img_LINE, leg->l.flags & FLAGS_MASK,
[a4ae909]455                           sprint_prefix(stn1->name->up),
456                           POS(stn2, 0), POS(stn2, 1), POS(stn2, 2));
[e6cfe52]457            if (!(leg->l.reverse & FLAG_ARTICULATION)) {
[25ab06b]458#ifdef BLUNDER_DETECTION
[e6cfe52]459               delta err;
460               int do_blunder;
[25ab06b]461#else
[e6cfe52]462               if (fhErrStat) {
463                  fprint_prefix(fhErrStat, stn1->name);
464                  fputs(szLink, fhErrStat);
465                  fprint_prefix(fhErrStat, stn2->name);
466               }
[402c753]467#endif
[e6cfe52]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]);
[045c055]474#ifndef NO_COVARIANCES
[f795df0]475                  /* FIXME: what about covariances? */
[e6cfe52]476                  hTotTheo = leg->v[0] + leg->v[1];
477                  vTotTheo = leg->v[2];
[0a208f9]478                  eTotTheo = hTotTheo + vTotTheo;
[045c055]479#else
[e6cfe52]480                  hTotTheo = leg->v[0] + leg->v[1];
481                  vTotTheo = leg->v[2];
[f7c455c]482                  eTotTheo = hTotTheo + vTotTheo;
[0a208f9]483#endif
[647407d]484#ifdef BLUNDER_DETECTION
[a8c4cfa]485                  memcpy(&err, &e, sizeof(delta));
[e6cfe52]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);
[cb3d1e2]499               }
[045c055]500            }
501         }
502      }
503   }
504
505   while (ptr != NULL) {
506      /* work out where traverse should be reconnected */
[eb18f4d]507      linkfor *leg = ptr->join1;
[045c055]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);
[be97baf]520      printf("<%p>[%d]%s...%s", stn1, i, szLink, szLink);
[045c055]521      print_prefix(stn2->name);
[be97baf]522      printf("<%p>[%d]\n", stn2, j);
[045c055]523#endif
[e6cfe52]524
[4c07c51]525      SVX_ASSERT(fixed(stn1));
526      SVX_ASSERT(fixed(stn2));
[e6cfe52]527
[045c055]528      /* calculate scaling factors for error distribution */
[e6cfe52]529      eTot = 0.0;
530      hTot = vTot = 0.0;
[4c07c51]531      SVX_ASSERT(data_here(stn1->leg[i]));
[e6cfe52]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      }
[045c055]542#ifndef NO_COVARIANCES
[f795df0]543      /* FIXME: what about covariances? */
[e6cfe52]544      hTotTheo = stn1->leg[i]->v[0] + stn1->leg[i]->v[1];
545      vTotTheo = stn1->leg[i]->v[2];
[045c055]546#else
[e6cfe52]547      hTotTheo = stn1->leg[i]->v[0] + stn1->leg[i]->v[1];
548      vTotTheo = stn1->leg[i]->v[2];
[045c055]549#endif
[f7c455c]550      eTotTheo = hTotTheo + vTotTheo;
[e6cfe52]551      cLegsTrav = 0;
552      lenTrav = 0.0;
[a4ae909]553      img_write_item(pimg, img_MOVE, 0, NULL,
554                     POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
[e6cfe52]555
[402c753]556      fArtic = stn1->leg[i]->l.reverse & FLAG_ARTICULATION;
[045c055]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
[e6cfe52]564      delta err;
565      int do_blunder;
[a8c4cfa]566      memcpy(&err, &e, sizeof(delta));
[e6cfe52]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      }
[045c055]577#endif
[e6cfe52]578      while (fTrue) {
579         int reached_end;
[693388e]580         prefix *leg_pfx;
[421b7d2]581
[e6cfe52]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]);
[4c07c51]587         SVX_ASSERT2(stn3->leg[k]->l.to == stn1,
[e6cfe52]588                 "reverse leg doesn't reciprocate");
[421b7d2]589
[e6cfe52]590         reached_end = (stn3 == stn2 && k == j);
[421b7d2]591
[e6cfe52]592         if (data_here(stn1->leg[i])) {
[693388e]593            leg_pfx = stn1->name->up;
[e6cfe52]594            leg = stn1->leg[i];
[045c055]595#ifdef BLUNDER_DETECTION
[e6cfe52]596            if (do_blunder && fhErrStat)
597               do_gross(err, leg->d, stn1, stn3, eTotTheo);
[045c055]598#endif
[e6cfe52]599            if (!reached_end)
600               adddd(&POSD(stn3), &POSD(stn1), &leg->d);
601         } else {
[693388e]602            leg_pfx = stn3->name->up;
[e6cfe52]603            leg = stn3->leg[k];
[045c055]604#ifdef BLUNDER_DETECTION
[e6cfe52]605            if (do_blunder && fhErrStat)
606               do_gross(err, leg->d, stn1, stn3, eTotTheo);
[045c055]607#endif
[e6cfe52]608            if (!reached_end)
609               subdd(&POSD(stn3), &POSD(stn1), &leg->d);
610         }
[421b7d2]611
[e6cfe52]612         lenTot = sqrdd(leg->d);
[421b7d2]613
[be97baf]614         if (!fZeros(&leg->v)) fEquate = fFalse;
[e6cfe52]615         if (!reached_end) {
616            add_stn_to_list(&stnlist, stn3);
[be97baf]617            if (!fEquate) {
[e6cfe52]618               mulsd(&e, &leg->v, &sc);
619               adddd(&POSD(stn3), &POSD(stn3), &e);
[95c3272]620            }
[e6cfe52]621            fix(stn3);
622         }
[421b7d2]623
[64d37a3]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
[a4ae909]633            SVX_ASSERT(!fEquate);
634            SVX_ASSERT(!fZeros(&leg->v));
635            if (leg->meta) {
[1ee204e]636                pimg->days1 = leg->meta->days1;
637                pimg->days2 = leg->meta->days2;
[a4ae909]638            } else {
[1ee204e]639                pimg->days1 = pimg->days2 = -1;
[64d37a3]640            }
[eb5aea0]641            pimg->style = (leg->l.flags >> FLAGS_STYLE_BIT0) & 0x07;
642            img_write_item(pimg, img_LINE, leg->l.flags & FLAGS_MASK,
[a4ae909]643                           sprint_prefix(leg_pfx),
644                           POS(stn3, 0), POS(stn3, 1), POS(stn3, 2));
[64d37a3]645         }
[045c055]646
[e6cfe52]647         /* FIXME: equate at the start of a traverse treated specially
[421b7d2]648          * - what about equates at end? */
[be97baf]649         if (stn1->name != stn3->name && !(fEquate && cLegsTrav == 0)) {
[a4ae909]650            /* (node not part of same stn) &&
[e6cfe52]651             * (not equate at start of traverse) */
[647407d]652#ifndef BLUNDER_DETECTION
[e6cfe52]653            if (fhErrStat && !fArtic) {
[be97baf]654               if (!stn1->name->ident) {
[e6cfe52]655                  /* FIXME: not ideal */
656                  fputs("<fixed point>", fhErrStat);
657               } else {
[be97baf]658                  fprint_prefix(fhErrStat, stn1->name);
[e6cfe52]659               }
660               fputs(fEquate ? szLinkEq : szLink, fhErrStat);
661               if (reached_end) {
[ff6cfe1]662                  if (!stn3->name->ident) {
[5b256a2]663                     /* FIXME: not ideal */
664                     fputs("<fixed point>", fhErrStat);
665                  } else {
[e6cfe52]666                     fprint_prefix(fhErrStat, stn3->name);
[5b256a2]667                  }
[647407d]668               }
[e6cfe52]669            }
[045c055]670#endif
[e6cfe52]671            if (!fEquate) {
672               cLegsTrav++;
673               lenTrav += sqrt(lenTot);
674            }
675         } else {
[045c055]676#if SHOW_INTERNAL_LEGS
[e6cfe52]677            if (fhErrStat && !fArtic) fprintf(fhErrStat, "+");
[045c055]678#endif
[e6cfe52]679            if (lenTot > 0.0) {
[045c055]680#if DEBUG_INVALID
[e6cfe52]681               fprintf(stderr, "lenTot = %8.4f ", lenTot);
[be97baf]682               fprint_prefix(stderr, stn1->name);
[e6cfe52]683               fprintf(stderr, " -> ");
684               fprint_prefix(stderr, stn3->name);
[045c055]685#endif
[e6cfe52]686               BUG("during calculation of closure errors");
[045c055]687            }
[e6cfe52]688         }
689         if (reached_end) break;
[421b7d2]690
[e6cfe52]691         i = k ^ 1; /* flip direction for other leg of 2 node */
[421b7d2]692
[e6cfe52]693         stn1 = stn3;
694      } /* endwhile */
[421b7d2]695
[e6cfe52]696      if (cLegsTrav && !fArtic && fhErrStat)
697         err_stat(cLegsTrav, lenTrav, eTot, eTotTheo,
698                  hTot, hTotTheo, vTot, vTotTheo);
[421b7d2]699
[045c055]700      ptrOld = ptr;
701      ptr = ptr->next;
702      osfree(ptrOld);
703   }
704
[f1067a2]705   /* Leave fhErrStat open in case we're asked to close loops again... */
[045c055]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{
[c61aa79]714   double E = sqrt(eTot / eTotTheo);
715   double H = sqrt(hTot / hTotTheo);
716   double V = sqrt(vTot / vTotTheo);
[647407d]717   if (!fSuppress) {
[c61aa79]718      double sqrt_eTot = sqrt(eTot);
[cb3d1e2]719      fputnl(fhErrStat);
[034141d]720      fprintf(fhErrStat, msg(/*Original length %6.2fm (%3d legs), moved %6.2fm (%5.2fm/leg). */145),
[cb3d1e2]721              lenTrav, cLegsTrav, sqrt_eTot, sqrt_eTot / cLegsTrav);
722      if (lenTrav > 0.0)
[034141d]723         fprintf(fhErrStat, msg(/*Error %6.2f%%*/146), 100 * sqrt_eTot / lenTrav);
[cb3d1e2]724      else
[421b7d2]725         fputs(msg(/*Error    N/A*/147), fhErrStat);
[cb3d1e2]726      fputnl(fhErrStat);
[c61aa79]727      fprintf(fhErrStat, "%f\n", E);
728      fprintf(fhErrStat, "H: %f V: %f\n", H, V);
[cb3d1e2]729      fputnl(fhErrStat);
730   }
[c61aa79]731   img_write_errors(pimg, cLegsTrav, lenTrav, E, H, V);
[045c055]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
[09bfd4c]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 */
[045c055]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;
[4c07c51]768      SVX_ASSERT(fixed(stn1));
[a4ae909]769      img_write_item(pimg, img_MOVE, 0, NULL,
770                     POS(stn1, 0), POS(stn1, 1), POS(stn1, 2));
[045c055]771
[e6cfe52]772      while (1) {
[693388e]773         prefix *leg_pfx;
[e6cfe52]774         int j;
[693388e]775
[e6cfe52]776         leg = stn1->leg[i];
777         stn2 = leg->l.to;
778         j = reverse_leg_dirn(leg);
779         if (data_here(leg)) {
[693388e]780            leg_pfx = stn1->name->up;
[e6cfe52]781            adddd(&POSD(stn2), &POSD(stn1), &leg->d);
[045c055]782#if 0
[e6cfe52]783            printf("Adding leg (%f, %f, %f)\n", leg->d[0], leg->d[1], leg->d[2]);
[045c055]784#endif
[e6cfe52]785         } else {
[693388e]786            leg_pfx = stn2->name->up;
[e6cfe52]787            leg = stn2->leg[j];
788            subdd(&POSD(stn2), &POSD(stn1), &leg->d);
[045c055]789#if 0
[e6cfe52]790            printf("Subtracting reverse leg (%f, %f, %f)\n", leg->d[0], leg->d[1], leg->d[2]);
[045c055]791#endif
[e6cfe52]792         }
[045c055]793
[e6cfe52]794         fix(stn2);
795         add_stn_to_list(&stnlist, stn2);
[64d37a3]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             }
[e6cfe52]804         }
[a4ae909]805         if (!(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
806            SVX_ASSERT(!fZeros(&leg->v));
807            if (leg->meta) {
[1ee204e]808                pimg->days1 = leg->meta->days1;
809                pimg->days2 = leg->meta->days2;
[a4ae909]810            } else {
[1ee204e]811                pimg->days1 = pimg->days2 = -1;
[693388e]812            }
[eb5aea0]813            pimg->style = (leg->l.flags >> FLAGS_STYLE_BIT0) & 0x07;
814            img_write_item(pimg, img_LINE, leg->l.flags & FLAGS_MASK,
[a4ae909]815                           sprint_prefix(leg_pfx),
816                           POS(stn2, 0), POS(stn2, 1), POS(stn2, 2));
[e6cfe52]817         }
[045c055]818
[e6cfe52]819         /* stop if not 2 node */
820         if (!two_node(stn2)) break;
[045c055]821
[e6cfe52]822         stn1 = stn2;
823         i = j ^ 1; /* flip direction for other leg of 2 node */
[045c055]824      }
825
826      ptrOld = ptrTrail;
827      ptrTrail = ptrTrail->next;
828      osfree(ptrOld);
829   }
830
[647407d]831   /* write out connections with no survey data */
[a4ae909]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);
[647407d]842      }
[a4ae909]843      img_write_item(pimg, img_MOVE, 0, NULL,
844                     POS(p->fr, 0), POS(p->fr, 1), POS(p->fr, 2));
[ee05463]845      if (p->meta) {
[1ee204e]846          pimg->days1 = p->meta->days1;
847          pimg->days2 = p->meta->days2;
[a4ae909]848      } else {
[1ee204e]849          pimg->days1 = pimg->days2 = -1;
[a4ae909]850      }
[eb5aea0]851      pimg->style = img_STYLE_NOSURVEY;
852      img_write_item(pimg, img_LINE, (p->flags & FLAGS_MASK),
[a4ae909]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);
[647407d]857   }
858
[045c055]859   /* write stations to .3d file and free legs and stations */
860   FOR_EACH_STN(stn1, stnlist) {
[e6cfe52]861      int d;
[4c07c51]862      SVX_ASSERT(fixed(stn1));
[a2c33ae]863      if (stn1->name->stn == stn1) {
[a4ae909]864         int sf = stn1->name->sflags;
[a2c33ae]865         /* take care of unused fixed points */
[a4ae909]866         if (!TSTBIT(sf, SFLAGS_SOLVED)) {
[a2c33ae]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            }
[95c3272]881         }
[e6cfe52]882      }
883      /* update coords of bounding box, ignoring the base positions
[c9eb197]884       * of points fixed with error estimates and only counting stations
[a2c33ae]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)) {
[e6cfe52]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;
[045c055]896            }
[e6cfe52]897            if (POS(stn1, d) > max[d]) {
898               max[d] = POS(stn1, d);
899               pfxHi[d] = stn1->name;
[045c055]900            }
901         }
[e6cfe52]902      }
[421b7d2]903
[e6cfe52]904      d = stn1->name->shape;
[f15cde77]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;
[a2c33ae]912            if (!pfx->ident && !TSTBIT(pfx->sflags, SFLAGS_ANON)) {
[f15cde77]913               /* Unused fixed point with error estimates */
914               unused_fixed_point = fTrue;
915            }
916         }
917         if (unused_fixed_point) {
[1edaf8d]918            warning_in_file(stn1->name->filename, stn1->name->line,
[0804fbe]919                    /*Unused fixed point “%s”*/73, sprint_prefix(stn1->name));
[045c055]920         }
921      }
[eb04711]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       */
[a2c33ae]926      if (stn1->leg[0] && !stn1->leg[0]->l.to->name->ident &&
927          !TSTBIT(stn1->leg[0]->l.to->name->sflags, SFLAGS_ANON))
[eb04711]928         stn1->name->shape--;
929
[045c055]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)) {
[eb18f4d]934            linkfor *legRev;
[045c055]935            node *stnB;
936            int iB;
937            stnB = leg->l.to;
938            iB = reverse_leg_dirn(leg);
939            legRev = stnB->leg[iB];
[4c07c51]940            SVX_ASSERT2(legRev->l.to == stn1, "leg doesn't reciprocate");
941            SVX_ASSERT(fixed(stn1));
[e6cfe52]942            if (!(leg->l.flags &
[95c3272]943                  (BIT(FLAGS_DUPLICATE)|BIT(FLAGS_SPLAY)|
944                   BIT(FLAGS_SURFACE)))) {
[693388e]945               /* check not an equating leg, or one inside an sdfix point */
946               if (!(leg->l.reverse & (FLAG_REPLACEMENTLEG | FLAG_FAKE))) {
[045c055]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));
[27b8b59]951                  totplan += hypot(leg->d[0], leg->d[1]);
[045c055]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}
[ee05463]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;
[d333899]983         prefix *pfx;
[ee05463]984         const char *name;
985         pimg->l = xsect->l;
986         pimg->r = xsect->r;
987         pimg->u = xsect->u;
988         pimg->d = xsect->d;
[b08ad81]989         if (xsect->meta) {
[1ee204e]990             pimg->days1 = xsect->meta->days1;
991             pimg->days2 = xsect->meta->days2;
[b08ad81]992         } else {
[1ee204e]993             pimg->days1 = pimg->days2 = -1;
[b08ad81]994         }
[d333899]995
996         pfx = xsect->stn;
997         name = sprint_prefix(pfx);
[ee05463]998         oldx = xsect;
999         xsect = xsect->next;
1000         osfree(oldx);
[d333899]1001
1002         if (!pfx->pos) {
1003             error_in_file(pfx->filename, pfx->line,
[0804fbe]1004                           /*Cross section specified at non-existent station “%s”*/83,
[d333899]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         }
[ee05463]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.