source: git/src/netbits.c @ 66be513

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

Fix component counting bugs

The component count was wrong in some cases, and we calculate the number
of loops using this component count, so the loop count would be wrong by
the same amount in these cases.

  • Property mode set to 100644
File size: 22.5 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
[bf9faf6]379replace_pfx_(node *stn, node *from, pos *pos_with, bool move_to_fixedlist)
[be374fc]380{
[bf9faf6]381   SVX_ASSERT(!fixed(stn));
382   if (move_to_fixedlist) {
383      SVX_ASSERT(pos_fixed(pos_with));
384      SVX_ASSERT(!fixed(stn));
385      remove_stn_from_list(&stnlist, stn);
386      add_stn_to_list(&fixedlist, stn);
387   }
[be374fc]388   stn->name->pos = pos_with;
[4b493d2]389   for (int d = 0; d < 3; d++) {
[be374fc]390      linkfor *leg = stn->leg[d];
391      if (!leg) break;
[4b493d2]392      node *to = leg->l.to;
[be374fc]393      if (to == from) continue;
394
395      if (fZeros(data_here(leg) ? &leg->v : &reverse_leg(leg)->v))
[bf9faf6]396         replace_pfx_(to, stn, pos_with, move_to_fixedlist);
[be374fc]397   }
398}
399
400/* We used to iterate over the whole station list (inefficient) - now we
401 * just look at any neighbouring nodes to see if they are equated */
402static void
[bf9faf6]403replace_pfx(const prefix *pfx_replace, const prefix *pfx_with,
404            bool move_to_fixedlist)
[be374fc]405{
[4c07c51]406   SVX_ASSERT(pfx_replace);
407   SVX_ASSERT(pfx_with);
[4b493d2]408   pos *pos_replace = pfx_replace->pos;
[4c07c51]409   SVX_ASSERT(pos_replace != pfx_with->pos);
[be374fc]410
[bf9faf6]411   replace_pfx_(pfx_replace->stn, NULL, pfx_with->pos, move_to_fixedlist);
[be374fc]412
413#if DEBUG_INVALID
[b0fe306]414   for (node *stn = stnlist; stn; stn = stn->next) {
415      SVX_ASSERT(stn->name->pos != pos_replace);
[be374fc]416   }
[bf9faf6]417   for (node *stn = fixedlist; stn; stn = stn->next) {
418      SVX_ASSERT(stn->name->pos != pos_replace);
419   }
[be374fc]420#endif
421
422   /* free the (now-unused) old pos */
423   osfree(pos_replace);
424}
425
[4b493d2]426// Add equating leg between existing stations whose names are name1 and name2.
[a420b49]427void
[be374fc]428process_equate(prefix *name1, prefix *name2)
[a420b49]429{
[dda0ca7]430   clear_last_leg();
[be374fc]431   if (name1 == name2) {
432      /* catch something like *equate "fred fred" */
[736f7df]433      /* TRANSLATORS: Here "station" is a survey station, not a train station.
434       */
[cab0f26]435      compile_diagnostic(DIAG_WARN, /*Station “%s” equated to itself*/13,
436                         sprint_prefix(name1));
[be374fc]437      return;
438   }
[4b493d2]439   node *stn1 = StnFromPfx(name1);
440   node *stn2 = StnFromPfx(name2);
[be374fc]441   /* equate nodes if not already equated */
[925fa451]442   if (name1->pos != name2->pos) {
[be374fc]443      if (pfx_fixed(name1)) {
[bf9faf6]444         bool name2_fixed = pfx_fixed(name2);
445         if (name2_fixed) {
[be374fc]446            /* both are fixed, but let them off iff their coordinates match */
447            char *s = osstrdup(sprint_prefix(name1));
[4b493d2]448            for (int d = 2; d >= 0; d--) {
[be374fc]449               if (name1->pos->p[d] != name2->pos->p[d]) {
[cab0f26]450                  compile_diagnostic(DIAG_ERR, /*Tried to equate two non-equal fixed stations: “%s” and “%s”*/52,
451                                     s, sprint_prefix(name2));
[be374fc]452                  osfree(s);
453                  return;
454               }
455            }
[736f7df]456            /* TRANSLATORS: "equal" as in:
457             *
458             * *fix a 1 2 3
459             * *fix b 1 2 3
460             * *equate a b */
[cab0f26]461            compile_diagnostic(DIAG_WARN, /*Equating two equal fixed points: “%s” and “%s”*/53,
462                               s, sprint_prefix(name2));
[be374fc]463            osfree(s);
464         }
[925fa451]465
[be374fc]466         /* name1 is fixed, so replace all refs to name2's pos with name1's */
[bf9faf6]467         replace_pfx(name2, name1, !name2_fixed);
[be374fc]468      } else {
469         /* name1 isn't fixed, so replace all refs to its pos with name2's */
[bf9faf6]470         replace_pfx(name1, name2, pfx_fixed(name2));
[be374fc]471      }
472
473      /* count equates as legs for now... */
474      cLegs++;
475      addleg_(stn1, stn2,
476              (real)0.0, (real)0.0, (real)0.0,
477              (real)0.0, (real)0.0, (real)0.0,
[7a05e07]478#ifndef NO_COVARIANCES
[be374fc]479              (real)0.0, (real)0.0, (real)0.0,
[7a05e07]480#endif
[be374fc]481              FLAG_FAKE);
482   }
[d1b1380]483}
484
485/* Add a 'fake' leg (not counted) between existing stations *fr and *to
[2140502]486 * (which *must* be different)
[d1b1380]487 * If either node is a three node, then it is split into two
488 * and the data structure adjusted as necessary
489 */
[a420b49]490void
491addfakeleg(node *fr, node *to,
492           real dx, real dy, real dz,
493           real vx, real vy, real vz
[7a05e07]494#ifndef NO_COVARIANCES
[a420b49]495           , real cyz, real czx, real cxy
[7a05e07]496#endif
[a420b49]497           )
498{
[dda0ca7]499   clear_last_leg();
[693388e]500   addleg_(fr, to, dx, dy, dz, vx, vy, vz,
[8cf2e04]501#ifndef NO_COVARIANCES
[693388e]502           cyz, czx, cxy,
[8cf2e04]503#endif
[693388e]504           FLAG_FAKE);
[d1b1380]505}
506
[78d2394]507static char
[a420b49]508freeleg(node **stnptr)
509{
[4b493d2]510   node *stn = *stnptr;
[7a05e07]511
[a420b49]512   if (stn->leg[0] == NULL) return 0; /* leg[0] unused */
513   if (stn->leg[1] == NULL) return 1; /* leg[1] unused */
514   if (stn->leg[2] == NULL) return 2; /* leg[2] unused */
[d1b1380]515
516   /* All legs used, so split node in two */
[4b493d2]517   node *newstn = osnew(node);
518   linkfor *leg = osnew(linkfor);
519   linkfor *leg2 = (linkfor*)osnew(linkrev);
[d1b1380]520
[4b493d2]521   *stnptr = newstn;
[d1b1380]522
[bf9faf6]523   add_stn_to_list(fixed(stn) ? &fixedlist : &stnlist, newstn);
[4b493d2]524   newstn->name = stn->name;
[d1b1380]525
[4b493d2]526   leg->l.to = newstn;
[a420b49]527   leg->d[0] = leg->d[1] = leg->d[2] = (real)0.0;
[7a05e07]528
[8cf2e04]529#ifndef NO_COVARIANCES
[4b493d2]530   for (int i = 0; i < 6; i++) leg->v[i] = (real)0.0;
[8cf2e04]531#else
[a420b49]532   leg->v[0] = leg->v[1] = leg->v[2] = (real)0.0;
[8cf2e04]533#endif
[693388e]534   leg->l.reverse = 1 | FLAG_DATAHERE | FLAG_FAKE;
[fdffa7d]535   leg->l.flags = pcs->flags | (pcs->recorded_style << FLAGS_STYLE_BIT0);
[d1b1380]536
[4b493d2]537   leg2->l.to = stn;
[a420b49]538   leg2->l.reverse = 0;
[d1b1380]539
[4b493d2]540   // NB this preserves pos->stn->leg[0] pointing to the "real" fixed point
541   // for stations fixed with error estimates.
542   newstn->leg[0] = stn->leg[0];
543   // Update the reverse leg.
544   reverse_leg(newstn->leg[0])->l.to = newstn;
545   newstn->leg[1] = leg2;
[d1b1380]546
[4b493d2]547   stn->leg[0] = leg;
[d1b1380]548
[4b493d2]549   newstn->leg[2] = NULL; /* needed as newstn->leg[dirn]==NULL indicates unused */
[d1b1380]550
[4b493d2]551   return 2; /* leg[2] unused */
[d1b1380]552}
553
[a420b49]554node *
555StnFromPfx(prefix *name)
556{
[4b493d2]557   if (name->stn != NULL) return name->stn;
558   node *stn = osnew(node);
[a420b49]559   stn->name = name;
[bf9faf6]560   bool fixed = false;
[a420b49]561   if (name->pos == NULL) {
562      name->pos = osnew(pos);
[d1b1380]563      unfix(stn);
[bf9faf6]564   } else {
565      fixed = pfx_fixed(name);
[d1b1380]566   }
[a420b49]567   stn->leg[0] = stn->leg[1] = stn->leg[2] = NULL;
[bf9faf6]568   add_stn_to_list(fixed ? &fixedlist : &stnlist, stn);
[a420b49]569   name->stn = stn;
[d1b1380]570   cStns++;
571   return stn;
572}
573
[a420b49]574extern void
[a862ee8]575fprint_prefix(FILE *fh, const prefix *ptr)
[a420b49]576{
[4c07c51]577   SVX_ASSERT(ptr);
[a2c33ae]578   if (TSTBIT(ptr->sflags, SFLAGS_ANON)) {
579      /* We release the stations, so ptr->stn is NULL late on, so we can't
580       * use that to print "anonymous station surveyed from somesurvey.12"
581       * here.  FIXME */
582      fputs("anonymous station", fh);
[55a0527]583      /* FIXME: if ident is set, show it? */
[a2c33ae]584      return;
585   }
[a420b49]586   if (ptr->up != NULL) {
587      fprint_prefix(fh, ptr->up);
[5d59477]588      if (ptr->up->up != NULL) fputc(output_separator, fh);
[ba84079]589      SVX_ASSERT(prefix_ident(ptr));
590      fputs(prefix_ident(ptr), fh);
[d1b1380]591   }
592}
593
[ee2e333]594static char *buffer = NULL;
[95d4862]595static OSSIZE_T buffer_len = 256;
[ee2e333]596
[95d4862]597static OSSIZE_T
[ee2e333]598sprint_prefix_(const prefix *ptr)
[a420b49]599{
[95d4862]600   OSSIZE_T len = 1;
[8cf2e04]601   if (ptr->up != NULL) {
[ba84079]602      const char *ident = prefix_ident(ptr);
603      SVX_ASSERT(ident);
[5d59477]604      len = sprint_prefix_(ptr->up);
[fcf1954]605      OSSIZE_T end = len - 1;
[ee2e333]606      if (ptr->up->up != NULL) len++;
[ba84079]607      len += strlen(ident);
[ee2e333]608      if (len > buffer_len) {
609         buffer = osrealloc(buffer, len);
610         buffer_len = len;
[a420b49]611      }
[fcf1954]612      char *p = buffer + end;
[5d59477]613      if (ptr->up->up != NULL) *p++ = output_separator;
[ba84079]614      strcpy(p, ident);
[d1b1380]615   }
[ee2e333]616   return len;
[d1b1380]617}
618
[a420b49]619extern char *
[a862ee8]620sprint_prefix(const prefix *ptr)
[a420b49]621{
[4c07c51]622   SVX_ASSERT(ptr);
[ee2e333]623   if (!buffer) buffer = osmalloc(buffer_len);
[a2c33ae]624   if (TSTBIT(ptr->sflags, SFLAGS_ANON)) {
625      /* We release the stations, so ptr->stn is NULL late on, so we can't
626       * use that to print "anonymous station surveyed from somesurvey.12"
627       * here.  FIXME */
[657fcee]628      strcpy(buffer, "anonymous station");
[55a0527]629      /* FIXME: if ident is set, show it? */
[a2c33ae]630      return buffer;
631   }
[ee2e333]632   *buffer = '\0';
633   sprint_prefix_(ptr);
[a420b49]634   return buffer;
[d1b1380]635}
636
[59f2dbb]637/* r = ab ; r,a,b are variance matrices */
638void
[298e2f3]639mulss(var *r, const svar *a, const svar *b)
[59f2dbb]640{
641#ifdef NO_COVARIANCES
642   /* variance-only version */
643   (*r)[0] = (*a)[0] * (*b)[0];
644   (*r)[1] = (*a)[1] * (*b)[1];
645   (*r)[2] = (*a)[2] * (*b)[2];
646#else
647#if 0
[298e2f3]648   SVX_ASSERT((const var *)r != a);
649   SVX_ASSERT((const var *)r != b);
[59f2dbb]650#endif
651
652   check_svar(a);
653   check_svar(b);
654
[4b493d2]655   for (int i = 0; i < 3; i++) {
656      for (int j = 0; j < 3; j++) {
657         real tot = 0;
658         for (int k = 0; k < 3; k++) {
[59f2dbb]659            tot += SN(a,i,k) * SN(b,k,j);
660         }
661         (*r)[i][j] = tot;
662      }
663   }
664   check_var(r);
665#endif
666}
667
[78d2394]668#ifndef NO_COVARIANCES
[59f2dbb]669/* r = ab ; r,a,b are variance matrices */
670void
[298e2f3]671smulvs(svar *r, const var *a, const svar *b)
[59f2dbb]672{
673#if 0
[298e2f3]674   SVX_ASSERT((const var *)r != a);
[59f2dbb]675#endif
[298e2f3]676   SVX_ASSERT((const svar *)r != b);
[59f2dbb]677
678   check_var(a);
679   check_svar(b);
680
681   (*r)[3]=(*r)[4]=(*r)[5]=-999;
[4b493d2]682   for (int i = 0; i < 3; i++) {
683      for (int j = 0; j < 3; j++) {
684         real tot = 0;
685         for (int k = 0; k < 3; k++) {
[59f2dbb]686            tot += (*a)[i][k] * SN(b,k,j);
687         }
688         if (i <= j)
689            SN(r,i,j) = tot;
690         else if (fabs(SN(r,j,i) - tot) > THRESHOLD) {
691            printf("not sym - %d,%d = %f, %d,%d was %f\n",
692                   i,j,tot,j,i,SN(r,j,i));
693            BUG("smulvs didn't produce a sym mx\n");
694         }
695      }
696   }
697   check_svar(r);
698}
[d1b1380]699#endif
700
[59f2dbb]701/* r = vb ; r,b delta vectors; a variance matrix */
702void
[298e2f3]703mulsd(delta *r, const svar *v, const delta *b)
[59f2dbb]704{
705#ifdef NO_COVARIANCES
706   /* variance-only version */
707   (*r)[0] = (*v)[0] * (*b)[0];
708   (*r)[1] = (*v)[1] * (*b)[1];
709   (*r)[2] = (*v)[2] * (*b)[2];
710#else
[298e2f3]711   SVX_ASSERT((const delta*)r != b);
[59f2dbb]712   check_svar(v);
713   check_d(b);
714
[4b493d2]715   for (int i = 0; i < 3; i++) {
716      real tot = 0;
717      for (int j = 0; j < 3; j++) tot += S(i,j) * (*b)[j];
[59f2dbb]718      (*r)[i] = tot;
719   }
720   check_d(r);
721#endif
722}
723
724/* r = ca ; r,a variance matrices; c real scaling factor  */
725void
[298e2f3]726mulsc(svar *r, const svar *a, real c)
[59f2dbb]727{
728#ifdef NO_COVARIANCES
729   /* variance-only version */
730   (*r)[0] = (*a)[0] * c;
731   (*r)[1] = (*a)[1] * c;
732   (*r)[2] = (*a)[2] * c;
733#else
734   check_svar(a);
[4b493d2]735   for (int i = 0; i < 6; i++) (*r)[i] = (*a)[i] * c;
[59f2dbb]736   check_svar(r);
737#endif
738}
739
[d1b1380]740/* r = a + b ; r,a,b delta vectors */
[a420b49]741void
[298e2f3]742adddd(delta *r, const delta *a, const delta *b)
[a420b49]743{
[5d26a94]744   check_d(a);
745   check_d(b);
[d1b1380]746   (*r)[0] = (*a)[0] + (*b)[0];
747   (*r)[1] = (*a)[1] + (*b)[1];
748   (*r)[2] = (*a)[2] + (*b)[2];
[5d26a94]749   check_d(r);
[d1b1380]750}
751
752/* r = a - b ; r,a,b delta vectors */
[a420b49]753void
[298e2f3]754subdd(delta *r, const delta *a, const delta *b) {
[5d26a94]755   check_d(a);
756   check_d(b);
[d1b1380]757   (*r)[0] = (*a)[0] - (*b)[0];
758   (*r)[1] = (*a)[1] - (*b)[1];
759   (*r)[2] = (*a)[2] - (*b)[2];
[5d26a94]760   check_d(r);
[d1b1380]761}
762
[59f2dbb]763/* r = a + b ; r,a,b variance matrices */
764void
[298e2f3]765addss(svar *r, const svar *a, const svar *b)
[59f2dbb]766{
767#ifdef NO_COVARIANCES
768   /* variance-only version */
769   (*r)[0] = (*a)[0] + (*b)[0];
770   (*r)[1] = (*a)[1] + (*b)[1];
771   (*r)[2] = (*a)[2] + (*b)[2];
772#else
773   check_svar(a);
774   check_svar(b);
[4b493d2]775   for (int i = 0; i < 6; i++) (*r)[i] = (*a)[i] + (*b)[i];
[59f2dbb]776   check_svar(r);
777#endif
778}
779
780/* r = a - b ; r,a,b variance matrices */
781void
[298e2f3]782subss(svar *r, const svar *a, const svar *b)
[59f2dbb]783{
784#ifdef NO_COVARIANCES
785   /* variance-only version */
786   (*r)[0] = (*a)[0] - (*b)[0];
787   (*r)[1] = (*a)[1] - (*b)[1];
788   (*r)[2] = (*a)[2] - (*b)[2];
789#else
790   check_svar(a);
791   check_svar(b);
[4b493d2]792   for (int i = 0; i < 6; i++) (*r)[i] = (*a)[i] - (*b)[i];
[59f2dbb]793   check_svar(r);
794#endif
795}
796
[7a05e07]797/* inv = v^-1 ; inv,v variance matrices */
[f98f8a5]798extern int
[298e2f3]799invert_svar(svar *inv, const svar *v)
[f98f8a5]800{
[78d2394]801#ifdef NO_COVARIANCES
[4b493d2]802   for (int i = 0; i < 3; i++) {
[42d23c5]803      if ((*v)[i] == 0.0) return 0; /* matrix is singular */
[f98f8a5]804      (*inv)[i] = 1.0 / (*v)[i];
805   }
806#else
[59f2dbb]807#if 0
[298e2f3]808   SVX_ASSERT((const var *)inv != v);
[59f2dbb]809#endif
810
811   check_svar(v);
[dac18d8]812   /* a d e
813    * d b f
814    * e f c
815    */
[4b493d2]816   real a = (*v)[0], b = (*v)[1], c = (*v)[2];
817   real d = (*v)[3], e = (*v)[4], f = (*v)[5];
818   real bcff = b * c - f * f;
819   real efcd = e * f - c * d;
820   real dfbe = d * f - b * e;
821   real det = a * bcff + d * efcd + e * dfbe;
[59f2dbb]822
[42d23c5]823   if (det == 0.0) {
[59f2dbb]824      /* printf("det=%.20f\n", det); */
825      return 0; /* matrix is singular */
826   }
827
828   det = 1 / det;
829
[dac18d8]830   (*inv)[0] = det * bcff;
831   (*inv)[1] = det * (c * a - e * e);
832   (*inv)[2] = det * (a * b - d * d);
833   (*inv)[3] = det * efcd;
834   (*inv)[4] = det * dfbe;
835   (*inv)[5] = det * (e * d - a * f);
[59f2dbb]836
[38193a5]837#if 0
838   /* This test fires very occasionally, and there's not much point in
839    * it anyhow - the matrix inversion algorithm is simple enough that
840    * we can be confident it's correctly implemented, so we might as
841    * well save the cycles and not perform this check.
842    */
[59f2dbb]843     { /* check that original * inverse = identity matrix */
[b4fe9fb]844        int i;
[59f2dbb]845        var p;
[dac18d8]846        real D = 0;
847        mulss(&p, v, inv);
[59f2dbb]848        for (i = 0; i < 3; i++) {
[dac18d8]849           int j;
850           for (j = 0; j < 3; j++) D += fabs(p[i][j] - (real)(i==j));
[59f2dbb]851        }
[dac18d8]852        if (D > THRESHOLD) {
[59f2dbb]853           printf("original * inverse=\n");
[dac18d8]854           print_svar(*v);
[59f2dbb]855           printf("*\n");
[dac18d8]856           print_svar(*inv);
[59f2dbb]857           printf("=\n");
858           print_var(p);
859           BUG("matrix didn't invert");
860        }
[dac18d8]861        check_svar(inv);
[59f2dbb]862     }
[78d2394]863#endif
[38193a5]864#endif
[59f2dbb]865   return 1;
866}
867
[d1b1380]868/* r = (b^-1)a ; r,a delta vectors; b variance matrix */
[78d2394]869#ifndef NO_COVARIANCES
[a420b49]870void
[298e2f3]871divds(delta *r, const delta *a, const svar *b)
[a420b49]872{
[d1b1380]873#ifdef NO_COVARIANCES
874   /* variance-only version */
875   (*r)[0] = (*a)[0] / (*b)[0];
876   (*r)[1] = (*a)[1] / (*b)[1];
877   (*r)[2] = (*a)[2] / (*b)[2];
878#else
[59f2dbb]879   svar b_inv;
[dac18d8]880   if (!invert_svar(&b_inv, b)) {
[59f2dbb]881      print_svar(*b);
882      BUG("covariance matrix is singular");
883   }
884   mulsd(r, &b_inv, a);
[d1b1380]885#endif
886}
[78d2394]887#endif
[d1b1380]888
[a420b49]889bool
[298e2f3]890fZeros(const svar *v) {
[d1b1380]891#ifdef NO_COVARIANCES
892   /* variance-only version */
[a420b49]893   return ((*v)[0] == 0.0 && (*v)[1] == 0.0 && (*v)[2] == 0.0);
[d1b1380]894#else
[59f2dbb]895   check_svar(v);
[4b493d2]896   for (int i = 0; i < 6; i++) if ((*v)[i] != 0.0) return false;
[59f2dbb]897
[63d4f07]898   return true;
[59f2dbb]899#endif
[dac18d8]900}
Note: See TracBrowser for help on using the repository browser.