source: git/src/netbits.c @ 0c323ec

RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernlogstereowalls-datawalls-data-hanging-as-warning
Last change on this file since 0c323ec was 736f7df, checked in by Olly Betts <olly@…>, 10 years ago

lib/extract-msgs.pl,lib/survex.pot,src/: Insert "TRANSLATORS"
comments into source code.

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