source: git/src/netbits.c @ e315359

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

Fix wrong "unused fixed point" warning with *solve

Also fixes double counting stations that are referenced both before and
after *solve.

See #86

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