source: git/src/netbits.c @ a72ed95

RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-datawalls-data-hanging-as-warning
Last change on this file since a72ed95 was dda0ca7, checked in by Olly Betts <olly@…>, 9 years ago

src/datain.c,src/netbits.c,src/netbits.h,tests/: If the same leg is
repeated consecutively, average the readings and treat as a single
leg.

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