source: git/src/netbits.c @ c981e5b

main
Last change on this file since c981e5b was 8048d405, checked in by Olly Betts <olly@…>, 2 months ago

Separate linkcommon reverse and flag bits

We had at least 2 spare bytes of padding, so we can store the reverse
direction separately which seems cleaner (and slightly more efficient
but the difference is so small it's only measureable using cachegrind).

  • Property mode set to 100644
File size: 23.0 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;
[8048d405]296   leg2->l.bits = 0;
297   leg->l.reverse = j;
298   leg->l.bits = FLAG_DATAHERE | leg_flags;
[693388e]299
[fdffa7d]300   leg->l.flags = pcs->flags | (pcs->recorded_style << FLAGS_STYLE_BIT0);
[b5a3219]301   leg->meta = pcs->meta;
302   if (pcs->meta) ++pcs->meta->ref_count;
[693388e]303
304   fr->leg[i] = leg;
305   to->leg[j] = leg2;
306
[dda0ca7]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
[e315359]367   /* Suppress "unused fixed point" warnings for these stations. */
[69bc51a]368   fr_name->sflags |= BIT(SFLAGS_USED);
369   to_name->sflags |= BIT(SFLAGS_USED);
[e315359]370
[dda0ca7]371   last_leg.to_name = to_name;
372   last_leg.fr_name = fr_name;
373   last_leg.n = 1;
374   last_leg.leg = addleg_(fr, to, dx, dy, dz, vx, vy, vz,
[2140502]375#ifndef NO_COVARIANCES
[dda0ca7]376                          cyz, czx, cxy,
[2140502]377#endif
[dda0ca7]378                          0);
[2140502]379}
380
[be374fc]381/* helper function for replace_pfx */
382static void
[bf9faf6]383replace_pfx_(node *stn, node *from, pos *pos_with, bool move_to_fixedlist)
[be374fc]384{
[bf9faf6]385   if (move_to_fixedlist) {
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
[9b1d5fc]404replace_pfx(const prefix *pfx_replace, const prefix *pfx_with)
[be374fc]405{
[4c07c51]406   SVX_ASSERT(pfx_replace);
407   SVX_ASSERT(pfx_with);
[9b1d5fc]408   bool move_to_fixedlist = !pfx_fixed(pfx_replace) && pfx_fixed(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 */
[ae917b96]424   free(pos_replace);
[be374fc]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));
[ae917b96]453                  free(s);
[be374fc]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));
[ae917b96]464            free(s);
[be374fc]465         }
[925fa451]466
[be374fc]467         /* name1 is fixed, so replace all refs to name2's pos with name1's */
[9b1d5fc]468         replace_pfx(name2, name1);
[be374fc]469      } else {
470         /* name1 isn't fixed, so replace all refs to its pos with name2's */
[9b1d5fc]471         replace_pfx(name1, name2);
[be374fc]472      }
473
[e315359]474      /* Suppress "unused fixed point" warnings for these stations. */
[69bc51a]475      name1->sflags |= BIT(SFLAGS_USED);
476      name2->sflags |= BIT(SFLAGS_USED);
[e315359]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
[8048d405]540   leg->l.reverse = 1;
541   leg->l.bits = FLAG_DATAHERE | FLAG_FAKE;
[fdffa7d]542   leg->l.flags = pcs->flags | (pcs->recorded_style << FLAGS_STYLE_BIT0);
[d1b1380]543
[4b493d2]544   leg2->l.to = stn;
[a420b49]545   leg2->l.reverse = 0;
[8048d405]546   leg2->l.bits = 0;
[d1b1380]547
[4b493d2]548   // NB this preserves pos->stn->leg[0] pointing to the "real" fixed point
549   // for stations fixed with error estimates.
550   newstn->leg[0] = stn->leg[0];
551   // Update the reverse leg.
552   reverse_leg(newstn->leg[0])->l.to = newstn;
553   newstn->leg[1] = leg2;
[d1b1380]554
[4b493d2]555   stn->leg[0] = leg;
[d1b1380]556
[4b493d2]557   newstn->leg[2] = NULL; /* needed as newstn->leg[dirn]==NULL indicates unused */
[d1b1380]558
[4b493d2]559   return 2; /* leg[2] unused */
[d1b1380]560}
561
[a420b49]562node *
563StnFromPfx(prefix *name)
564{
[4b493d2]565   if (name->stn != NULL) return name->stn;
566   node *stn = osnew(node);
[a420b49]567   stn->name = name;
[bf9faf6]568   bool fixed = false;
[a420b49]569   if (name->pos == NULL) {
570      name->pos = osnew(pos);
[d1b1380]571      unfix(stn);
[bf9faf6]572   } else {
573      fixed = pfx_fixed(name);
[d1b1380]574   }
[a420b49]575   stn->leg[0] = stn->leg[1] = stn->leg[2] = NULL;
[bf9faf6]576   add_stn_to_list(fixed ? &fixedlist : &stnlist, stn);
[a420b49]577   name->stn = stn;
[e315359]578   // Don't re-count a station which already exists from before a `*solve`.
579   // After we solve we delete and NULL-out its `node*`, but set SFLAGS_SOLVED.
580   if (!TSTBIT(name->sflags, SFLAGS_SOLVED)) cStns++;
[d1b1380]581   return stn;
582}
583
[a420b49]584extern void
[a862ee8]585fprint_prefix(FILE *fh, const prefix *ptr)
[a420b49]586{
[4c07c51]587   SVX_ASSERT(ptr);
[a2c33ae]588   if (TSTBIT(ptr->sflags, SFLAGS_ANON)) {
589      /* We release the stations, so ptr->stn is NULL late on, so we can't
590       * use that to print "anonymous station surveyed from somesurvey.12"
591       * here.  FIXME */
592      fputs("anonymous station", fh);
[55a0527]593      /* FIXME: if ident is set, show it? */
[a2c33ae]594      return;
595   }
[a420b49]596   if (ptr->up != NULL) {
597      fprint_prefix(fh, ptr->up);
[5d59477]598      if (ptr->up->up != NULL) fputc(output_separator, fh);
[ba84079]599      SVX_ASSERT(prefix_ident(ptr));
600      fputs(prefix_ident(ptr), fh);
[d1b1380]601   }
602}
603
[ee2e333]604static char *buffer = NULL;
[ae917b96]605static size_t buffer_len = 256;
[ee2e333]606
[ae917b96]607static size_t
[ee2e333]608sprint_prefix_(const prefix *ptr)
[a420b49]609{
[ae917b96]610   size_t len = 1;
[8cf2e04]611   if (ptr->up != NULL) {
[ba84079]612      const char *ident = prefix_ident(ptr);
613      SVX_ASSERT(ident);
[5d59477]614      len = sprint_prefix_(ptr->up);
[ae917b96]615      size_t end = len - 1;
[ee2e333]616      if (ptr->up->up != NULL) len++;
[ba84079]617      len += strlen(ident);
[ee2e333]618      if (len > buffer_len) {
619         buffer = osrealloc(buffer, len);
620         buffer_len = len;
[a420b49]621      }
[fcf1954]622      char *p = buffer + end;
[5d59477]623      if (ptr->up->up != NULL) *p++ = output_separator;
[ba84079]624      strcpy(p, ident);
[d1b1380]625   }
[ee2e333]626   return len;
[d1b1380]627}
628
[a420b49]629extern char *
[a862ee8]630sprint_prefix(const prefix *ptr)
[a420b49]631{
[4c07c51]632   SVX_ASSERT(ptr);
[ee2e333]633   if (!buffer) buffer = osmalloc(buffer_len);
[a2c33ae]634   if (TSTBIT(ptr->sflags, SFLAGS_ANON)) {
635      /* We release the stations, so ptr->stn is NULL late on, so we can't
636       * use that to print "anonymous station surveyed from somesurvey.12"
637       * here.  FIXME */
[657fcee]638      strcpy(buffer, "anonymous station");
[55a0527]639      /* FIXME: if ident is set, show it? */
[a2c33ae]640      return buffer;
641   }
[ee2e333]642   *buffer = '\0';
643   sprint_prefix_(ptr);
[a420b49]644   return buffer;
[d1b1380]645}
646
[59f2dbb]647/* r = ab ; r,a,b are variance matrices */
648void
[298e2f3]649mulss(var *r, const svar *a, const svar *b)
[59f2dbb]650{
651#ifdef NO_COVARIANCES
652   /* variance-only version */
653   (*r)[0] = (*a)[0] * (*b)[0];
654   (*r)[1] = (*a)[1] * (*b)[1];
655   (*r)[2] = (*a)[2] * (*b)[2];
656#else
657#if 0
[298e2f3]658   SVX_ASSERT((const var *)r != a);
659   SVX_ASSERT((const var *)r != b);
[59f2dbb]660#endif
661
662   check_svar(a);
663   check_svar(b);
664
[4b493d2]665   for (int i = 0; i < 3; i++) {
666      for (int j = 0; j < 3; j++) {
667         real tot = 0;
668         for (int k = 0; k < 3; k++) {
[59f2dbb]669            tot += SN(a,i,k) * SN(b,k,j);
670         }
671         (*r)[i][j] = tot;
672      }
673   }
674   check_var(r);
675#endif
676}
677
[78d2394]678#ifndef NO_COVARIANCES
[59f2dbb]679/* r = ab ; r,a,b are variance matrices */
680void
[298e2f3]681smulvs(svar *r, const var *a, const svar *b)
[59f2dbb]682{
683#if 0
[298e2f3]684   SVX_ASSERT((const var *)r != a);
[59f2dbb]685#endif
[298e2f3]686   SVX_ASSERT((const svar *)r != b);
[59f2dbb]687
688   check_var(a);
689   check_svar(b);
690
691   (*r)[3]=(*r)[4]=(*r)[5]=-999;
[4b493d2]692   for (int i = 0; i < 3; i++) {
693      for (int j = 0; j < 3; j++) {
694         real tot = 0;
695         for (int k = 0; k < 3; k++) {
[59f2dbb]696            tot += (*a)[i][k] * SN(b,k,j);
697         }
698         if (i <= j)
699            SN(r,i,j) = tot;
700         else if (fabs(SN(r,j,i) - tot) > THRESHOLD) {
701            printf("not sym - %d,%d = %f, %d,%d was %f\n",
702                   i,j,tot,j,i,SN(r,j,i));
703            BUG("smulvs didn't produce a sym mx\n");
704         }
705      }
706   }
707   check_svar(r);
708}
[d1b1380]709#endif
710
[59f2dbb]711/* r = vb ; r,b delta vectors; a variance matrix */
712void
[298e2f3]713mulsd(delta *r, const svar *v, const delta *b)
[59f2dbb]714{
715#ifdef NO_COVARIANCES
716   /* variance-only version */
717   (*r)[0] = (*v)[0] * (*b)[0];
718   (*r)[1] = (*v)[1] * (*b)[1];
719   (*r)[2] = (*v)[2] * (*b)[2];
720#else
[298e2f3]721   SVX_ASSERT((const delta*)r != b);
[59f2dbb]722   check_svar(v);
723   check_d(b);
724
[4b493d2]725   for (int i = 0; i < 3; i++) {
726      real tot = 0;
727      for (int j = 0; j < 3; j++) tot += S(i,j) * (*b)[j];
[59f2dbb]728      (*r)[i] = tot;
729   }
730   check_d(r);
731#endif
732}
733
734/* r = ca ; r,a variance matrices; c real scaling factor  */
735void
[298e2f3]736mulsc(svar *r, const svar *a, real c)
[59f2dbb]737{
738#ifdef NO_COVARIANCES
739   /* variance-only version */
740   (*r)[0] = (*a)[0] * c;
741   (*r)[1] = (*a)[1] * c;
742   (*r)[2] = (*a)[2] * c;
743#else
744   check_svar(a);
[4b493d2]745   for (int i = 0; i < 6; i++) (*r)[i] = (*a)[i] * c;
[59f2dbb]746   check_svar(r);
747#endif
748}
749
[d1b1380]750/* r = a + b ; r,a,b delta vectors */
[a420b49]751void
[298e2f3]752adddd(delta *r, const delta *a, const delta *b)
[a420b49]753{
[5d26a94]754   check_d(a);
755   check_d(b);
[d1b1380]756   (*r)[0] = (*a)[0] + (*b)[0];
757   (*r)[1] = (*a)[1] + (*b)[1];
758   (*r)[2] = (*a)[2] + (*b)[2];
[5d26a94]759   check_d(r);
[d1b1380]760}
761
762/* r = a - b ; r,a,b delta vectors */
[a420b49]763void
[298e2f3]764subdd(delta *r, const delta *a, const delta *b) {
[5d26a94]765   check_d(a);
766   check_d(b);
[d1b1380]767   (*r)[0] = (*a)[0] - (*b)[0];
768   (*r)[1] = (*a)[1] - (*b)[1];
769   (*r)[2] = (*a)[2] - (*b)[2];
[5d26a94]770   check_d(r);
[d1b1380]771}
772
[59f2dbb]773/* r = a + b ; r,a,b variance matrices */
774void
[298e2f3]775addss(svar *r, const svar *a, const svar *b)
[59f2dbb]776{
777#ifdef NO_COVARIANCES
778   /* variance-only version */
779   (*r)[0] = (*a)[0] + (*b)[0];
780   (*r)[1] = (*a)[1] + (*b)[1];
781   (*r)[2] = (*a)[2] + (*b)[2];
782#else
783   check_svar(a);
784   check_svar(b);
[4b493d2]785   for (int i = 0; i < 6; i++) (*r)[i] = (*a)[i] + (*b)[i];
[59f2dbb]786   check_svar(r);
787#endif
788}
789
790/* r = a - b ; r,a,b variance matrices */
791void
[298e2f3]792subss(svar *r, const svar *a, const svar *b)
[59f2dbb]793{
794#ifdef NO_COVARIANCES
795   /* variance-only version */
796   (*r)[0] = (*a)[0] - (*b)[0];
797   (*r)[1] = (*a)[1] - (*b)[1];
798   (*r)[2] = (*a)[2] - (*b)[2];
799#else
800   check_svar(a);
801   check_svar(b);
[4b493d2]802   for (int i = 0; i < 6; i++) (*r)[i] = (*a)[i] - (*b)[i];
[59f2dbb]803   check_svar(r);
804#endif
805}
806
[7a05e07]807/* inv = v^-1 ; inv,v variance matrices */
[f98f8a5]808extern int
[298e2f3]809invert_svar(svar *inv, const svar *v)
[f98f8a5]810{
[78d2394]811#ifdef NO_COVARIANCES
[4b493d2]812   for (int i = 0; i < 3; i++) {
[42d23c5]813      if ((*v)[i] == 0.0) return 0; /* matrix is singular */
[f98f8a5]814      (*inv)[i] = 1.0 / (*v)[i];
815   }
816#else
[59f2dbb]817#if 0
[298e2f3]818   SVX_ASSERT((const var *)inv != v);
[59f2dbb]819#endif
820
821   check_svar(v);
[dac18d8]822   /* a d e
823    * d b f
824    * e f c
825    */
[4b493d2]826   real a = (*v)[0], b = (*v)[1], c = (*v)[2];
827   real d = (*v)[3], e = (*v)[4], f = (*v)[5];
828   real bcff = b * c - f * f;
829   real efcd = e * f - c * d;
830   real dfbe = d * f - b * e;
831   real det = a * bcff + d * efcd + e * dfbe;
[59f2dbb]832
[42d23c5]833   if (det == 0.0) {
[59f2dbb]834      /* printf("det=%.20f\n", det); */
835      return 0; /* matrix is singular */
836   }
837
838   det = 1 / det;
839
[dac18d8]840   (*inv)[0] = det * bcff;
841   (*inv)[1] = det * (c * a - e * e);
842   (*inv)[2] = det * (a * b - d * d);
843   (*inv)[3] = det * efcd;
844   (*inv)[4] = det * dfbe;
845   (*inv)[5] = det * (e * d - a * f);
[59f2dbb]846
[38193a5]847#if 0
848   /* This test fires very occasionally, and there's not much point in
849    * it anyhow - the matrix inversion algorithm is simple enough that
850    * we can be confident it's correctly implemented, so we might as
851    * well save the cycles and not perform this check.
852    */
[59f2dbb]853     { /* check that original * inverse = identity matrix */
[b4fe9fb]854        int i;
[59f2dbb]855        var p;
[dac18d8]856        real D = 0;
857        mulss(&p, v, inv);
[59f2dbb]858        for (i = 0; i < 3; i++) {
[dac18d8]859           int j;
860           for (j = 0; j < 3; j++) D += fabs(p[i][j] - (real)(i==j));
[59f2dbb]861        }
[dac18d8]862        if (D > THRESHOLD) {
[59f2dbb]863           printf("original * inverse=\n");
[dac18d8]864           print_svar(*v);
[59f2dbb]865           printf("*\n");
[dac18d8]866           print_svar(*inv);
[59f2dbb]867           printf("=\n");
868           print_var(p);
869           BUG("matrix didn't invert");
870        }
[dac18d8]871        check_svar(inv);
[59f2dbb]872     }
[78d2394]873#endif
[38193a5]874#endif
[59f2dbb]875   return 1;
876}
877
[d1b1380]878/* r = (b^-1)a ; r,a delta vectors; b variance matrix */
[78d2394]879#ifndef NO_COVARIANCES
[a420b49]880void
[298e2f3]881divds(delta *r, const delta *a, const svar *b)
[a420b49]882{
[d1b1380]883#ifdef NO_COVARIANCES
884   /* variance-only version */
885   (*r)[0] = (*a)[0] / (*b)[0];
886   (*r)[1] = (*a)[1] / (*b)[1];
887   (*r)[2] = (*a)[2] / (*b)[2];
888#else
[59f2dbb]889   svar b_inv;
[dac18d8]890   if (!invert_svar(&b_inv, b)) {
[59f2dbb]891      print_svar(*b);
892      BUG("covariance matrix is singular");
893   }
894   mulsd(r, &b_inv, a);
[d1b1380]895#endif
896}
[78d2394]897#endif
[d1b1380]898
[a420b49]899bool
[298e2f3]900fZeros(const svar *v) {
[d1b1380]901#ifdef NO_COVARIANCES
902   /* variance-only version */
[a420b49]903   return ((*v)[0] == 0.0 && (*v)[1] == 0.0 && (*v)[2] == 0.0);
[d1b1380]904#else
[59f2dbb]905   check_svar(v);
[4b493d2]906   for (int i = 0; i < 6; i++) if ((*v)[i] != 0.0) return false;
[59f2dbb]907
[63d4f07]908   return true;
[59f2dbb]909#endif
[dac18d8]910}
Note: See TracBrowser for help on using the repository browser.