source: git/src/netbits.c @ 77bb9f4

stereo-2025
Last change on this file since 77bb9f4 was 77bb9f4, checked in by Olly Betts <olly@…>, 9 months ago

Optimise validity check in remove_stn_from_list()

We optionally check if the station is actually on the list, which
we were doing by scanning the whole list for the station. Instead
we can keep going back from the station to the list head and check
if that matches, which will scan only half the list on average.

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