source: git/src/netbits.c @ 76cf7f1

RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernloglog-selectwalls-datawalls-data-hanging-as-warning
Last change on this file since 76cf7f1 was 20e064b, checked in by Olly Betts <olly@…>, 5 years ago

Use isnan() to check for not-a-number

This is cleaner, more robust and more efficient than formatting the
number as a string and checking for "NaN" or "nan" in the result.

  • Property mode set to 100644
File size: 22.2 KB
RevLine 
[ff6cfe1]1/* netbits.c
[d1b1380]2 * Miscellaneous primitive network routines for Survex
[20e064b]3 * Copyright (C) 1992-2003,2006,2011,2013,2014,2015,2019 Olly Betts
[846746e]4 *
[89231c4]5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
[846746e]9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[89231c4]12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
[846746e]14 *
[89231c4]15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
[ecbc6c18]17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
[d1b1380]18 */
19
[a420b49]20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
[d1b1380]23
[f98f8a5]24#if 0
[b84a343]25# define DEBUG_INVALID 1
[f98f8a5]26#endif
27
[7a05e07]28#include "debug.h"
[a420b49]29#include "cavern.h"
[7a05e07]30#include "filename.h"
31#include "message.h"
[d1b1380]32#include "netbits.h"
[a420b49]33#include "datain.h" /* for compile_error */
[a838042]34#include "validate.h" /* for compile_error */
[20e064b]35#include <math.h>
[d1b1380]36
[dd368da]37#define THRESHOLD (REAL_EPSILON * 1000) /* 100 was too small */
[daf88e1]38
[564f471]39node *stn_iter = NULL; /* for FOR_EACH_STN */
40
[dda0ca7]41static struct {
42   prefix * to_name;
43   prefix * fr_name;
44   linkfor * leg;
45   int n;
46} last_leg = { NULL, NULL, NULL, 0 };
47
48void clear_last_leg(void) {
49   last_leg.to_name = NULL;
50}
51
[78d2394]52static char freeleg(node **stnptr);
53
[f98f8a5]54#ifdef NO_COVARIANCES
[407084d]55static void check_var(/*const*/ var *v) {
[647407d]56   int bad = 0;
57   int i;
58
59   for (i = 0; i < 3; i++) {
[20e064b]60      if (isnan(v[i])
[dac18d8]61         printf("*** NaN!!!\n"), bad = 1;
[647407d]62   }
63   if (bad) print_var(v);
64   return;
[f98f8a5]65}
66#else
[a862ee8]67#define V(A,B) ((*v)[A][B])
[407084d]68static void check_var(/*const*/ var *v) {
[a862ee8]69   int bad = 0;
70   int ok = 0;
71   int i, j;
[407084d]72#if DEBUG_INVALID
[a862ee8]73   real det = 0.0;
[407084d]74#endif
[a862ee8]75
76   for (i = 0; i < 3; i++) {
77      for (j = 0; j < 3; j++) {
[20e064b]78         if (isnan(V(i, j)))
[dac18d8]79            printf("*** NaN!!!\n"), bad = 1, ok = 1;
[a5da11c]80         if (V(i, j) != 0.0) ok = 1;
[a862ee8]81      }
82   }
83   if (!ok) return; /* ignore all-zero matrices */
84
[40fb2e4]85#if DEBUG_INVALID
[a862ee8]86   for (i = 0; i < 3; i++) {
[a5da11c]87      det += V(i, 0) * (V((i + 1) % 3, 1) * V((i + 2) % 3, 2) -
88                        V((i + 1) % 3, 2) * V((i + 2) % 3, 1));
[a862ee8]89   }
90
[daf88e1]91   if (fabs(det) < THRESHOLD)
[a862ee8]92      printf("*** Singular!!!\n"), bad = 1;
[40fb2e4]93#endif
[a862ee8]94
95#if 0
[840e496]96   /* don't check this - it isn't always the case! */
[daf88e1]97   if (fabs(V(0,1) - V(1,0)) > THRESHOLD ||
98       fabs(V(0,2) - V(2,0)) > THRESHOLD ||
99       fabs(V(1,2) - V(2,1)) > THRESHOLD)
[a862ee8]100      printf("*** Not symmetric!!!\n"), bad = 1;
101   if (V(0,0) <= 0.0 || V(1,1) <= 0.0 || V(2,2) <= 0.0)
102      printf("*** Not positive definite (diag <= 0)!!!\n"), bad = 1;
103   if (sqrd(V(0,1)) >= V(0,0)*V(1,1) || sqrd(V(0,2)) >= V(0,0)*V(2,2) ||
104       sqrd(V(1,0)) >= V(0,0)*V(1,1) || sqrd(V(2,0)) >= V(0,0)*V(2,2) ||
105       sqrd(V(1,2)) >= V(2,2)*V(1,1) || sqrd(V(2,1)) >= V(2,2)*V(1,1))
106      printf("*** Not positive definite (off diag^2 >= diag product)!!!\n"), bad = 1;
107#endif
108   if (bad) print_var(*v);
109}
[59f2dbb]110
111#define SN(V,A,B) ((*(V))[(A)==(B)?(A):2+(A)+(B)])
112#define S(A,B) SN(v,A,B)
113
114static void check_svar(/*const*/ svar *v) {
115   int bad = 0;
116   int ok = 0;
[dac18d8]117   int i;
[59f2dbb]118#if DEBUG_INVALID
119   real det = 0.0;
120#endif
121
[dac18d8]122   for (i = 0; i < 6; i++) {
[20e064b]123      if (isnan((*v)[i]))
[dac18d8]124         printf("*** NaN!!!\n"), bad = 1, ok = 1;
125      if ((*v)[i] != 0.0) ok = 1;
[59f2dbb]126   }
127   if (!ok) return; /* ignore all-zero matrices */
128
129#if DEBUG_INVALID
130   for (i = 0; i < 3; i++) {
131      det += S(i, 0) * (S((i + 1) % 3, 1) * S((i + 2) % 3, 2) -
132                        S((i + 1) % 3, 2) * S((i + 2) % 3, 1));
133   }
134
135   if (fabs(det) < THRESHOLD)
136      printf("*** Singular!!!\n"), bad = 1;
137#endif
138
[840e496]139#if 0
140   /* don't check this - it isn't always the case! */
[dac18d8]141   if ((*v)[0] <= 0.0 || (*v)[1] <= 0.0 || (*v)[2] <= 0.0)
[59f2dbb]142      printf("*** Not positive definite (diag <= 0)!!!\n"), bad = 1;
[dac18d8]143   if (sqrd((*v)[3]) >= (*v)[0]*(*v)[1] ||
144       sqrd((*v)[4]) >= (*v)[0]*(*v)[2] ||
145       sqrd((*v)[5]) >= (*v)[1]*(*v)[2])
[59f2dbb]146      printf("*** Not positive definite (off diag^2 >= diag product)!!!\n"), bad = 1;
[840e496]147#endif
[59f2dbb]148   if (bad) print_svar(*v);
149}
[f98f8a5]150#endif
[a862ee8]151
[eb18f4d]152static void check_d(/*const*/ delta *d) {
[5d26a94]153   int bad = 0;
154   int i;
155
156   for (i = 0; i < 3; i++) {
[20e064b]157      if (isnan((*d)[i]))
[dac18d8]158         printf("*** NaN!!!\n"), bad = 1;
[5d26a94]159   }
160
161   if (bad) printf("(%4.2f,%4.2f,%4.2f)\n", (*d)[0], (*d)[1], (*d)[2]);
162}
163
[564f471]164/* insert at head of double-linked list */
165void
166add_stn_to_list(node **list, node *stn) {
[4c07c51]167   SVX_ASSERT(list);
168   SVX_ASSERT(stn);
169   SVX_ASSERT(stn_iter != stn); /* if it does, we're still on a list... */
[85fe934]170#if 0
171   printf("add_stn_to_list(%p, [%p] ", list, stn);
172   if (stn->name) print_prefix(stn->name);
173   printf(")\n");
174#endif
[564f471]175   stn->next = *list;
176   stn->prev = NULL;
177   if (*list) (*list)->prev = stn;
178   *list = stn;
179}
180
181/* remove from double-linked list */
182void
183remove_stn_from_list(node **list, node *stn) {
[4c07c51]184   SVX_ASSERT(list);
185   SVX_ASSERT(stn);
[85fe934]186#if 0
187   printf("remove_stn_from_list(%p, [%p] ", list, stn);
188   if (stn->name) print_prefix(stn->name);
189   printf(")\n");
190#endif
[b84a343]191#if DEBUG_INVALID
[85fe934]192     {
193        /* check station is actually in this list */
194        node *stn_to_remove_is_in_list = *list;
195        validate();
196        while (stn_to_remove_is_in_list != stn) {
[4c07c51]197           SVX_ASSERT(stn_to_remove_is_in_list);
[85fe934]198           stn_to_remove_is_in_list = stn_to_remove_is_in_list->next;
199        }
200     }
201#endif
[564f471]202   /* adjust the iterator if it points to the element we're deleting */
203   if (stn_iter == stn) stn_iter = stn_iter->next;
204   /* need a special case if we're removing the list head */
205   if (stn->prev == NULL) {
206      *list = stn->next;
207      if (*list) (*list)->prev = NULL;
208   } else {
209      stn->prev->next = stn->next;
[28ddfe1]210      if (stn->next) stn->next->prev = stn->prev;
[564f471]211   }
212}
213
[d1b1380]214/* Create (uses osmalloc) a forward leg containing the data in leg, or
215 * the reversed data in the reverse of leg, if leg doesn't hold data
216 */
[2140502]217linkfor *
[a420b49]218copy_link(linkfor *leg)
219{
[d1b1380]220   linkfor *legOut;
221   int d;
[a420b49]222   legOut = osnew(linkfor);
[d1b1380]223   if (data_here(leg)) {
[a420b49]224      for (d = 2; d >= 0; d--) legOut->d[d] = leg->d[d];
[d1b1380]225   } else {
[a420b49]226      leg = reverse_leg(leg);
[4c07c51]227      SVX_ASSERT(data_here(leg));
[a420b49]228      for (d = 2; d >= 0; d--) legOut->d[d] = -leg->d[d];
[d1b1380]229   }
230#if 1
[7a05e07]231# ifndef NO_COVARIANCES
[59f2dbb]232   check_svar(&(leg->v));
[cb3d1e2]233     {
[59f2dbb]234        int i;
235        for (i = 0; i < 6; i++) legOut->v[i] = leg->v[i];
[d1b1380]236     }
[7a05e07]237# else
[a420b49]238   for (d = 2; d >= 0; d--) legOut->v[d] = leg->v[d];
[7a05e07]239# endif
[d1b1380]240#else
[59f2dbb]241   memcpy(legOut->v, leg->v, sizeof(svar));
[d1b1380]242#endif
[b5a3219]243   legOut->meta = pcs->meta;
244   if (pcs->meta) ++pcs->meta->ref_count;
[d1b1380]245   return legOut;
246}
247
[0804fbe]248/* Adds to the forward leg “leg”, the data in leg2, or the reversed data
[d1b1380]249 * in the reverse of leg2, if leg2 doesn't hold data
250 */
[2140502]251linkfor *
[a5da11c]252addto_link(linkfor *leg, const linkfor *leg2)
[a420b49]253{
[d1b1380]254   if (data_here(leg2)) {
[407084d]255      adddd(&leg->d, &leg->d, &((linkfor *)leg2)->d);
[d1b1380]256   } else {
[a420b49]257      leg2 = reverse_leg(leg2);
[4c07c51]258      SVX_ASSERT(data_here(leg2));
[407084d]259      subdd(&leg->d, &leg->d, &((linkfor *)leg2)->d);
[d1b1380]260   }
[59f2dbb]261   addss(&leg->v, &leg->v, &((linkfor *)leg2)->v);
[d1b1380]262   return leg;
263}
264
[dda0ca7]265static linkfor *
[693388e]266addleg_(node *fr, node *to,
267        real dx, real dy, real dz,
268        real vx, real vy, real vz,
269#ifndef NO_COVARIANCES
270        real cyz, real czx, real cxy,
271#endif
272        int leg_flags)
273{
274   int i, j;
275   linkfor *leg, *leg2;
276   /* we have been asked to add a leg with the same node at both ends
277    * - this should be trapped by the caller */
[4c07c51]278   SVX_ASSERT(fr->name != to->name);
[693388e]279
280   leg = osnew(linkfor);
281   leg2 = (linkfor*)osnew(linkrev);
282
283   i = freeleg(&fr);
284   j = freeleg(&to);
285
286   leg->l.to = to;
287   leg2->l.to = fr;
288   leg->d[0] = dx;
289   leg->d[1] = dy;
290   leg->d[2] = dz;
291#ifndef NO_COVARIANCES
292   leg->v[0] = vx;
293   leg->v[1] = vy;
294   leg->v[2] = vz;
295   leg->v[3] = cxy;
296   leg->v[4] = czx;
297   leg->v[5] = cyz;
298   check_svar(&(leg->v));
299#else
300   leg->v[0] = vx;
301   leg->v[1] = vy;
302   leg->v[2] = vz;
303#endif
304   leg2->l.reverse = i;
305   leg->l.reverse = j | FLAG_DATAHERE | leg_flags;
306
[eb5aea0]307   leg->l.flags = pcs->flags | (pcs->style << FLAGS_STYLE_BIT0);
[b5a3219]308   leg->meta = pcs->meta;
309   if (pcs->meta) ++pcs->meta->ref_count;
[693388e]310
311   fr->leg[i] = leg;
312   to->leg[j] = leg2;
313
[f15cde77]314   ++fr->name->shape;
315   ++to->name->shape;
[dda0ca7]316
317   return leg;
[693388e]318}
319
[be374fc]320/* Add a leg between names *fr_name and *to_name
321 * If either is a three node, then it is split into two
322 * and the data structure adjusted as necessary.
323 */
[2140502]324void
325addlegbyname(prefix *fr_name, prefix *to_name, bool fToFirst,
326             real dx, real dy, real dz,
327             real vx, real vy, real vz
328#ifndef NO_COVARIANCES
329             , real cyz, real czx, real cxy
330#endif
331             )
332{
333   node *to, *fr;
334   if (to_name == fr_name) {
[736f7df]335      /* TRANSLATORS: Here a "survey leg" is a set of measurements between two
336       * "survey stations".
[b49ac56]337       *
[736f7df]338       * %s is replaced by the name of the station. */
[cab0f26]339      compile_diagnostic(DIAG_ERR, /*Survey leg with same station (“%s”) at both ends - typing error?*/50,
340                         sprint_prefix(to_name));
[2140502]341      return;
[421b7d2]342   }
[2140502]343   if (fToFirst) {
344      to = StnFromPfx(to_name);
345      fr = StnFromPfx(fr_name);
346   } else {
347      fr = StnFromPfx(fr_name);
348      to = StnFromPfx(to_name);
349   }
[dda0ca7]350   if (last_leg.to_name) {
351      if (last_leg.to_name == to_name && last_leg.fr_name == fr_name) {
352         /* FIXME: Not the right way to average... */
353         linkfor * leg = last_leg.leg;
354         int n = last_leg.n++;
355         leg->d[0] = (leg->d[0] * n + dx) / (n + 1);
356         leg->d[1] = (leg->d[1] * n + dy) / (n + 1);
357         leg->d[2] = (leg->d[2] * n + dz) / (n + 1);
358#ifndef NO_COVARIANCES
359         leg->v[0] = (leg->v[0] * n + vx) / (n + 1);
360         leg->v[1] = (leg->v[1] * n + vy) / (n + 1);
361         leg->v[2] = (leg->v[2] * n + vz) / (n + 1);
362         leg->v[3] = (leg->v[3] * n + cxy) / (n + 1);
363         leg->v[4] = (leg->v[4] * n + czx) / (n + 1);
364         leg->v[5] = (leg->v[5] * n + cyz) / (n + 1);
365         check_svar(&(leg->v));
366#else
367         leg->v[0] = (leg->v[0] * n + vx) / (n + 1);
368         leg->v[1] = (leg->v[1] * n + vy) / (n + 1);
369         leg->v[2] = (leg->v[2] * n + vz) / (n + 1);
370#endif
371         return;
372      }
373   }
374   cLegs++;
375
376   last_leg.to_name = to_name;
377   last_leg.fr_name = fr_name;
378   last_leg.n = 1;
379   last_leg.leg = addleg_(fr, to, dx, dy, dz, vx, vy, vz,
[2140502]380#ifndef NO_COVARIANCES
[dda0ca7]381                          cyz, czx, cxy,
[2140502]382#endif
[dda0ca7]383                          0);
[2140502]384}
385
[be374fc]386/* helper function for replace_pfx */
387static void
388replace_pfx_(node *stn, node *from, pos *pos_replace, pos *pos_with)
389{
390   int d;
391   stn->name->pos = pos_with;
392   for (d = 0; d < 3; d++) {
393      linkfor *leg = stn->leg[d];
394      node *to;
395      if (!leg) break;
396      to = leg->l.to;
397      if (to == from) continue;
398
399      if (fZeros(data_here(leg) ? &leg->v : &reverse_leg(leg)->v))
400         replace_pfx_(to, stn, pos_replace, pos_with);
401   }
402}
403
404/* We used to iterate over the whole station list (inefficient) - now we
405 * just look at any neighbouring nodes to see if they are equated */
406static void
407replace_pfx(const prefix *pfx_replace, const prefix *pfx_with)
408{
409   pos *pos_replace;
[4c07c51]410   SVX_ASSERT(pfx_replace);
411   SVX_ASSERT(pfx_with);
[be374fc]412   pos_replace = pfx_replace->pos;
[4c07c51]413   SVX_ASSERT(pos_replace != pfx_with->pos);
[be374fc]414
415   replace_pfx_(pfx_replace->stn, NULL, pos_replace, pfx_with->pos);
416
417#if DEBUG_INVALID
418   {
419      node *stn;
420      FOR_EACH_STN(stn, stnlist) {
[4c07c51]421         SVX_ASSERT(stn->name->pos != pos_replace);
[be374fc]422      }
423   }
424#endif
425
426   /* free the (now-unused) old pos */
427   osfree(pos_replace);
428}
429
430/* Add an equating leg between existing stations *fr and *to (whose names are
431 * name1 and name2).
[d1b1380]432 */
[a420b49]433void
[be374fc]434process_equate(prefix *name1, prefix *name2)
[a420b49]435{
[925fa451]436   node *stn1, *stn2;
[dda0ca7]437   clear_last_leg();
[be374fc]438   if (name1 == name2) {
439      /* catch something like *equate "fred fred" */
[736f7df]440      /* TRANSLATORS: Here "station" is a survey station, not a train station.
441       */
[cab0f26]442      compile_diagnostic(DIAG_WARN, /*Station “%s” equated to itself*/13,
443                         sprint_prefix(name1));
[be374fc]444      return;
445   }
[925fa451]446   stn1 = StnFromPfx(name1);
447   stn2 = StnFromPfx(name2);
[be374fc]448   /* equate nodes if not already equated */
[925fa451]449   if (name1->pos != name2->pos) {
[be374fc]450      if (pfx_fixed(name1)) {
451         if (pfx_fixed(name2)) {
452            /* both are fixed, but let them off iff their coordinates match */
453            char *s = osstrdup(sprint_prefix(name1));
454            int d;
455            for (d = 2; d >= 0; d--) {
456               if (name1->pos->p[d] != name2->pos->p[d]) {
[cab0f26]457                  compile_diagnostic(DIAG_ERR, /*Tried to equate two non-equal fixed stations: “%s” and “%s”*/52,
458                                     s, sprint_prefix(name2));
[be374fc]459                  osfree(s);
460                  return;
461               }
462            }
[736f7df]463            /* TRANSLATORS: "equal" as in:
464             *
465             * *fix a 1 2 3
466             * *fix b 1 2 3
467             * *equate a b */
[cab0f26]468            compile_diagnostic(DIAG_WARN, /*Equating two equal fixed points: “%s” and “%s”*/53,
469                               s, sprint_prefix(name2));
[be374fc]470            osfree(s);
471         }
[925fa451]472
[be374fc]473         /* name1 is fixed, so replace all refs to name2's pos with name1's */
474         replace_pfx(name2, name1);
475      } else {
476         /* name1 isn't fixed, so replace all refs to its pos with name2's */
477         replace_pfx(name1, name2);
478      }
479
480      /* count equates as legs for now... */
481      cLegs++;
482      addleg_(stn1, stn2,
483              (real)0.0, (real)0.0, (real)0.0,
484              (real)0.0, (real)0.0, (real)0.0,
[7a05e07]485#ifndef NO_COVARIANCES
[be374fc]486              (real)0.0, (real)0.0, (real)0.0,
[7a05e07]487#endif
[be374fc]488              FLAG_FAKE);
489   }
[d1b1380]490}
491
492/* Add a 'fake' leg (not counted) between existing stations *fr and *to
[2140502]493 * (which *must* be different)
[d1b1380]494 * If either node is a three node, then it is split into two
495 * and the data structure adjusted as necessary
496 */
[a420b49]497void
498addfakeleg(node *fr, node *to,
499           real dx, real dy, real dz,
500           real vx, real vy, real vz
[7a05e07]501#ifndef NO_COVARIANCES
[a420b49]502           , real cyz, real czx, real cxy
[7a05e07]503#endif
[a420b49]504           )
505{
[dda0ca7]506   clear_last_leg();
[693388e]507   addleg_(fr, to, dx, dy, dz, vx, vy, vz,
[8cf2e04]508#ifndef NO_COVARIANCES
[693388e]509           cyz, czx, cxy,
[8cf2e04]510#endif
[693388e]511           FLAG_FAKE);
[d1b1380]512}
513
[78d2394]514static char
[a420b49]515freeleg(node **stnptr)
516{
[d1b1380]517   node *stn, *oldstn;
518   linkfor *leg, *leg2;
[94f6ef3]519#ifndef NO_COVARIANCES
[59f2dbb]520   int i;
[94f6ef3]521#endif
[7a05e07]522
[a420b49]523   stn = *stnptr;
[7a05e07]524
[a420b49]525   if (stn->leg[0] == NULL) return 0; /* leg[0] unused */
526   if (stn->leg[1] == NULL) return 1; /* leg[1] unused */
527   if (stn->leg[2] == NULL) return 2; /* leg[2] unused */
[d1b1380]528
529   /* All legs used, so split node in two */
[a420b49]530   oldstn = stn;
531   stn = osnew(node);
532   leg = osnew(linkfor);
533   leg2 = (linkfor*)osnew(linkrev);
[d1b1380]534
[a420b49]535   *stnptr = stn;
[d1b1380]536
[564f471]537   add_stn_to_list(&stnlist, stn);
[a420b49]538   stn->name = oldstn->name;
[d1b1380]539
[a420b49]540   leg->l.to = stn;
541   leg->d[0] = leg->d[1] = leg->d[2] = (real)0.0;
[7a05e07]542
[8cf2e04]543#ifndef NO_COVARIANCES
[59f2dbb]544   for (i = 0; i < 6; i++) leg->v[i] = (real)0.0;
[8cf2e04]545#else
[a420b49]546   leg->v[0] = leg->v[1] = leg->v[2] = (real)0.0;
[8cf2e04]547#endif
[693388e]548   leg->l.reverse = 1 | FLAG_DATAHERE | FLAG_FAKE;
[eb5aea0]549   leg->l.flags = pcs->flags | (pcs->style << FLAGS_STYLE_BIT0);
[d1b1380]550
[a420b49]551   leg2->l.to = oldstn;
552   leg2->l.reverse = 0;
[d1b1380]553
[eb04711]554   /* NB this preserves pos->stn->leg[0] to point to the "real" fixed point
555    * for stations fixed with error estimates
556    */
[a420b49]557   stn->leg[0] = oldstn->leg[0];
[d1b1380]558   /* correct reverse leg */
[a420b49]559   reverse_leg(stn->leg[0])->l.to = stn;
560   stn->leg[1] = leg2;
[d1b1380]561
[a420b49]562   oldstn->leg[0] = leg;
[d1b1380]563
[a420b49]564   stn->leg[2] = NULL; /* needed as stn->leg[dirn]==NULL indicates unused */
[d1b1380]565
566   return(2); /* leg[2] unused */
567}
568
[a420b49]569node *
570StnFromPfx(prefix *name)
571{
[d1b1380]572   node *stn;
[a420b49]573   if (name->stn != NULL) return (name->stn);
574   stn = osnew(node);
575   stn->name = name;
576   if (name->pos == NULL) {
577      name->pos = osnew(pos);
[d1b1380]578      unfix(stn);
579   }
[a420b49]580   stn->leg[0] = stn->leg[1] = stn->leg[2] = NULL;
[564f471]581   add_stn_to_list(&stnlist, stn);
[a420b49]582   name->stn = stn;
[d1b1380]583   cStns++;
584   return stn;
585}
586
[a420b49]587extern void
[a862ee8]588fprint_prefix(FILE *fh, const prefix *ptr)
[a420b49]589{
[4c07c51]590   SVX_ASSERT(ptr);
[a2c33ae]591   if (TSTBIT(ptr->sflags, SFLAGS_ANON)) {
592      /* We release the stations, so ptr->stn is NULL late on, so we can't
593       * use that to print "anonymous station surveyed from somesurvey.12"
594       * here.  FIXME */
595      fputs("anonymous station", fh);
[55a0527]596      /* FIXME: if ident is set, show it? */
[a2c33ae]597      return;
598   }
[a420b49]599   if (ptr->up != NULL) {
600      fprint_prefix(fh, ptr->up);
601      if (ptr->up->up != NULL) fputc('.', fh);
[4c07c51]602      SVX_ASSERT(ptr->ident);
[a420b49]603      fputs(ptr->ident, fh);
[d1b1380]604   }
605}
606
[ee2e333]607static char *buffer = NULL;
[95d4862]608static OSSIZE_T buffer_len = 256;
[ee2e333]609
[95d4862]610static OSSIZE_T
[ee2e333]611sprint_prefix_(const prefix *ptr)
[a420b49]612{
[95d4862]613   OSSIZE_T len = 1;
[8cf2e04]614   if (ptr->up != NULL) {
[4c07c51]615      SVX_ASSERT(ptr->ident);
[95d4862]616      len = sprint_prefix_(ptr->up) + strlen(ptr->ident);
[ee2e333]617      if (ptr->up->up != NULL) len++;
618      if (len > buffer_len) {
619         buffer = osrealloc(buffer, len);
620         buffer_len = len;
[a420b49]621      }
[ee2e333]622      if (ptr->up->up != NULL) strcat(buffer, ".");
623      strcat(buffer, ptr->ident);
[d1b1380]624   }
[ee2e333]625   return len;
[d1b1380]626}
627
[a420b49]628extern char *
[a862ee8]629sprint_prefix(const prefix *ptr)
[a420b49]630{
[4c07c51]631   SVX_ASSERT(ptr);
[ee2e333]632   if (!buffer) buffer = osmalloc(buffer_len);
[a2c33ae]633   if (TSTBIT(ptr->sflags, SFLAGS_ANON)) {
634      /* We release the stations, so ptr->stn is NULL late on, so we can't
635       * use that to print "anonymous station surveyed from somesurvey.12"
636       * here.  FIXME */
637      sprintf(buffer, "anonymous station");
[55a0527]638      /* FIXME: if ident is set, show it? */
[a2c33ae]639      return buffer;
640   }
[ee2e333]641   *buffer = '\0';
642   sprint_prefix_(ptr);
[a420b49]643   return buffer;
[d1b1380]644}
645
[59f2dbb]646/* r = ab ; r,a,b are variance matrices */
647void
648mulss(var *r, /*const*/ svar *a, /*const*/ svar *b)
649{
650#ifdef NO_COVARIANCES
651   /* variance-only version */
652   (*r)[0] = (*a)[0] * (*b)[0];
653   (*r)[1] = (*a)[1] * (*b)[1];
654   (*r)[2] = (*a)[2] * (*b)[2];
655#else
656   int i, j, k;
657   real tot;
658
659#if 0
[4c07c51]660   SVX_ASSERT((/*const*/ var *)r != a);
661   SVX_ASSERT((/*const*/ var *)r != b);
[59f2dbb]662#endif
663
664   check_svar(a);
665   check_svar(b);
666
667   for (i = 0; i < 3; i++) {
668      for (j = 0; j < 3; j++) {
669         tot = 0;
670         for (k = 0; k < 3; k++) {
671            tot += SN(a,i,k) * SN(b,k,j);
672         }
673         (*r)[i][j] = tot;
674      }
675   }
676   check_var(r);
677#endif
678}
679
[78d2394]680#ifndef NO_COVARIANCES
[59f2dbb]681/* r = ab ; r,a,b are variance matrices */
682void
683smulvs(svar *r, /*const*/ var *a, /*const*/ svar *b)
684{
685   int i, j, k;
686   real tot;
687
688#if 0
[4c07c51]689   SVX_ASSERT((/*const*/ var *)r != a);
[59f2dbb]690#endif
[4c07c51]691   SVX_ASSERT((/*const*/ svar *)r != b);
[59f2dbb]692
693   check_var(a);
694   check_svar(b);
695
696   (*r)[3]=(*r)[4]=(*r)[5]=-999;
697   for (i = 0; i < 3; i++) {
698      for (j = 0; j < 3; j++) {
699         tot = 0;
700         for (k = 0; k < 3; k++) {
701            tot += (*a)[i][k] * SN(b,k,j);
702         }
703         if (i <= j)
704            SN(r,i,j) = tot;
705         else if (fabs(SN(r,j,i) - tot) > THRESHOLD) {
706            printf("not sym - %d,%d = %f, %d,%d was %f\n",
707                   i,j,tot,j,i,SN(r,j,i));
708            BUG("smulvs didn't produce a sym mx\n");
709         }
710      }
711   }
712   check_svar(r);
713}
[d1b1380]714#endif
715
[59f2dbb]716/* r = vb ; r,b delta vectors; a variance matrix */
717void
718mulsd(delta *r, /*const*/ svar *v, /*const*/ delta *b)
719{
720#ifdef NO_COVARIANCES
721   /* variance-only version */
722   (*r)[0] = (*v)[0] * (*b)[0];
723   (*r)[1] = (*v)[1] * (*b)[1];
724   (*r)[2] = (*v)[2] * (*b)[2];
725#else
726   int i, j;
727   real tot;
728
[4c07c51]729   SVX_ASSERT((/*const*/ delta*)r != b);
[59f2dbb]730   check_svar(v);
731   check_d(b);
732
733   for (i = 0; i < 3; i++) {
734      tot = 0;
735      for (j = 0; j < 3; j++) tot += S(i,j) * (*b)[j];
736      (*r)[i] = tot;
737   }
738   check_d(r);
739#endif
740}
741
742/* r = ca ; r,a variance matrices; c real scaling factor  */
743void
744mulsc(svar *r, /*const*/ svar *a, real c)
745{
746#ifdef NO_COVARIANCES
747   /* variance-only version */
748   (*r)[0] = (*a)[0] * c;
749   (*r)[1] = (*a)[1] * c;
750   (*r)[2] = (*a)[2] * c;
751#else
752   int i;
753
754   check_svar(a);
755   for (i = 0; i < 6; i++) (*r)[i] = (*a)[i] * c;
756   check_svar(r);
757#endif
758}
759
[d1b1380]760/* r = a + b ; r,a,b delta vectors */
[a420b49]761void
[eb18f4d]762adddd(delta *r, /*const*/ delta *a, /*const*/ delta *b)
[a420b49]763{
[5d26a94]764   check_d(a);
765   check_d(b);
[d1b1380]766   (*r)[0] = (*a)[0] + (*b)[0];
767   (*r)[1] = (*a)[1] + (*b)[1];
768   (*r)[2] = (*a)[2] + (*b)[2];
[5d26a94]769   check_d(r);
[d1b1380]770}
771
772/* r = a - b ; r,a,b delta vectors */
[a420b49]773void
[eb18f4d]774subdd(delta *r, /*const*/ delta *a, /*const*/ delta *b) {
[5d26a94]775   check_d(a);
776   check_d(b);
[d1b1380]777   (*r)[0] = (*a)[0] - (*b)[0];
778   (*r)[1] = (*a)[1] - (*b)[1];
779   (*r)[2] = (*a)[2] - (*b)[2];
[5d26a94]780   check_d(r);
[d1b1380]781}
782
[59f2dbb]783/* r = a + b ; r,a,b variance matrices */
784void
785addss(svar *r, /*const*/ svar *a, /*const*/ svar *b)
786{
787#ifdef NO_COVARIANCES
788   /* variance-only version */
789   (*r)[0] = (*a)[0] + (*b)[0];
790   (*r)[1] = (*a)[1] + (*b)[1];
791   (*r)[2] = (*a)[2] + (*b)[2];
792#else
793   int i;
794
795   check_svar(a);
796   check_svar(b);
797   for (i = 0; i < 6; i++) (*r)[i] = (*a)[i] + (*b)[i];
798   check_svar(r);
799#endif
800}
801
802/* r = a - b ; r,a,b variance matrices */
803void
804subss(svar *r, /*const*/ svar *a, /*const*/ svar *b)
805{
806#ifdef NO_COVARIANCES
807   /* variance-only version */
808   (*r)[0] = (*a)[0] - (*b)[0];
809   (*r)[1] = (*a)[1] - (*b)[1];
810   (*r)[2] = (*a)[2] - (*b)[2];
811#else
812   int i;
813
814   check_svar(a);
815   check_svar(b);
816   for (i = 0; i < 6; i++) (*r)[i] = (*a)[i] - (*b)[i];
817   check_svar(r);
818#endif
819}
820
[7a05e07]821/* inv = v^-1 ; inv,v variance matrices */
[f98f8a5]822extern int
[78d2394]823invert_svar(svar *inv, /*const*/ svar *v)
[f98f8a5]824{
[78d2394]825#ifdef NO_COVARIANCES
[f98f8a5]826   int i;
827   for (i = 0; i < 3; i++) {
[42d23c5]828      if ((*v)[i] == 0.0) return 0; /* matrix is singular */
[f98f8a5]829      (*inv)[i] = 1.0 / (*v)[i];
830   }
831#else
[dac18d8]832   real det, a, b, c, d, e, f, bcff, efcd, dfbe;
[59f2dbb]833
834#if 0
[4c07c51]835   SVX_ASSERT((/*const*/ var *)inv != v);
[59f2dbb]836#endif
837
838   check_svar(v);
[dac18d8]839   /* a d e
840    * d b f
841    * e f c
842    */
843   a = (*v)[0], b = (*v)[1], c = (*v)[2];
844   d = (*v)[3], e = (*v)[4], f = (*v)[5];
845   bcff = b * c - f * f;
846   efcd = e * f - c * d;
847   dfbe = d * f - b * e;
848   det = a * bcff + d * efcd + e * dfbe;
[59f2dbb]849
[42d23c5]850   if (det == 0.0) {
[59f2dbb]851      /* printf("det=%.20f\n", det); */
852      return 0; /* matrix is singular */
853   }
854
855   det = 1 / det;
856
[dac18d8]857   (*inv)[0] = det * bcff;
858   (*inv)[1] = det * (c * a - e * e);
859   (*inv)[2] = det * (a * b - d * d);
860   (*inv)[3] = det * efcd;
861   (*inv)[4] = det * dfbe;
862   (*inv)[5] = det * (e * d - a * f);
[59f2dbb]863
[38193a5]864#if 0
865   /* This test fires very occasionally, and there's not much point in
866    * it anyhow - the matrix inversion algorithm is simple enough that
867    * we can be confident it's correctly implemented, so we might as
868    * well save the cycles and not perform this check.
869    */
[59f2dbb]870     { /* check that original * inverse = identity matrix */
[b4fe9fb]871        int i;
[59f2dbb]872        var p;
[dac18d8]873        real D = 0;
874        mulss(&p, v, inv);
[59f2dbb]875        for (i = 0; i < 3; i++) {
[dac18d8]876           int j;
877           for (j = 0; j < 3; j++) D += fabs(p[i][j] - (real)(i==j));
[59f2dbb]878        }
[dac18d8]879        if (D > THRESHOLD) {
[59f2dbb]880           printf("original * inverse=\n");
[dac18d8]881           print_svar(*v);
[59f2dbb]882           printf("*\n");
[dac18d8]883           print_svar(*inv);
[59f2dbb]884           printf("=\n");
885           print_var(p);
886           BUG("matrix didn't invert");
887        }
[dac18d8]888        check_svar(inv);
[59f2dbb]889     }
[78d2394]890#endif
[38193a5]891#endif
[59f2dbb]892   return 1;
893}
894
[d1b1380]895/* r = (b^-1)a ; r,a delta vectors; b variance matrix */
[78d2394]896#ifndef NO_COVARIANCES
[a420b49]897void
[78d2394]898divds(delta *r, /*const*/ delta *a, /*const*/ svar *b)
[a420b49]899{
[d1b1380]900#ifdef NO_COVARIANCES
901   /* variance-only version */
902   (*r)[0] = (*a)[0] / (*b)[0];
903   (*r)[1] = (*a)[1] / (*b)[1];
904   (*r)[2] = (*a)[2] / (*b)[2];
905#else
[59f2dbb]906   svar b_inv;
[dac18d8]907   if (!invert_svar(&b_inv, b)) {
[59f2dbb]908      print_svar(*b);
909      BUG("covariance matrix is singular");
910   }
911   mulsd(r, &b_inv, a);
[d1b1380]912#endif
913}
[78d2394]914#endif
[d1b1380]915
[a420b49]916bool
[dac18d8]917fZeros(/*const*/ svar *v) {
[d1b1380]918#ifdef NO_COVARIANCES
919   /* variance-only version */
[a420b49]920   return ((*v)[0] == 0.0 && (*v)[1] == 0.0 && (*v)[2] == 0.0);
[d1b1380]921#else
[59f2dbb]922   int i;
923
924   check_svar(v);
925   for (i = 0; i < 6; i++) if ((*v)[i] != 0.0) return fFalse;
926
927   return fTrue;
928#endif
[dac18d8]929}
Note: See TracBrowser for help on using the repository browser.