source: git/src/netbits.c @ f78034b

stereo-2025
Last change on this file since f78034b was 298e2f3, checked in by Olly Betts <olly@…>, 12 months ago

Uncomment const qualifiers

These were commented out in 2001, apparently to fix compiler
warnings but restoring them doesn't result in warnings with
modern GCC at least.

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