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

main
Last change on this file since 8a7804fb was 0b99107, checked in by Olly Betts <olly@…>, 3 months ago

Eliminate old FSF addresses

Update GPL/LGPL licence files and boilerplate to direct people who
didn't receive the licence text to the FSF website, as the current
versions of the FSF licence texts now do, rather than giving a postal
address.

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