source: git/src/netbits.c @ 8d74d05

stereo-2025
Last change on this file since 8d74d05 was c77682a, checked in by Olly Betts <olly@…>, 5 months ago

Stop reporting node stats

These are kind of interesting, but since the advent of surveying with
Disto-X and similar devices which make it quick to shoot multiple
splay legs from each station the number of larger order nodes has
increased and this information is now quite verbose and any utility
it had has substantially declined.

If they're still wanted they could make a reappearance in the future in
aven, with splays excluded when counting the number of legs at each
station.

Fixes #86, reported by Wookey.

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