source: git/src/extend.c @ f96897b

faster-cavernlogwalls-datawalls-data-hanging-as-warning
Last change on this file since f96897b was 4c83f84, checked in by Olly Betts <olly@…>, 3 weeks ago

Don't check HAVE_CONFIG_H in most cases

This check is only useful for img.c, which is intended to be usable
outside of Survex (and had fallbacks for functions which may not be
available which will get used if built in a non-autotools project).
For all the other source files it's just useless boilerplate.

  • Property mode set to 100644
File size: 22.1 KB
Line 
1/* extend.c
2 * Produce an extended elevation
3 * Copyright (C) 1995-2002,2005,2010,2011,2013,2014,2016,2017 Olly Betts
4 * Copyright (C) 2004,2005 John Pybus
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20
21#include <config.h>
22
23#include <float.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "cmdline.h"
29#include "debug.h"
30#include "filelist.h"
31#include "filename.h"
32#include "hash.h"
33#include "img_hosted.h"
34#include "message.h"
35#include "useful.h"
36
37/* To save memory we should probably use the prefix hash for the prefix on
38 * point labels (FIXME) */
39
40typedef struct stn {
41   const char *label;
42   int flags;
43   const struct stn *next;
44} stn;
45
46typedef struct splay {
47   struct POINT *pt;
48   struct splay *next;
49} splay;
50
51typedef struct POINT {
52   img_point p;
53   double X;
54   const stn *stns;
55   unsigned int order;
56   char dir;
57   char fDone;
58   char fBroken;
59   splay *splays;
60   struct POINT *next;
61} point;
62
63typedef struct LEG {
64   point *fr, *to;
65   const char *prefix;
66   char dir;
67   char fDone;
68   char broken;
69   int flags;
70   struct LEG *next;
71} leg;
72
73/* Values for leg.broken: */
74#define BREAK_FR    0x01
75#define BREAK_TO    0x02
76
77/* Values for point.dir and leg.dir: */
78#define ELEFT  0x01
79#define ERIGHT 0x02
80#define ESWAP  0x04
81
82static point headpoint = {{0, 0, 0}, 0, NULL, 0, 0, 0, 0, NULL, NULL};
83
84static leg headleg = {NULL, NULL, NULL, 0, 0, 0, 0, NULL};
85
86static img *pimg_out;
87
88static int show_breaks = 0;
89
90static void do_stn(point *, double, const char *, int, int, double, double);
91
92typedef struct pfx {
93   const char *label;
94   struct pfx *next;
95} pfx;
96
97static pfx **htab;
98
99#define HTAB_SIZE 0x2000
100
101static const char *
102find_prefix(const char *prefix)
103{
104   pfx *p;
105   int hash;
106
107   SVX_ASSERT(prefix);
108
109   hash = hash_string(prefix) & (HTAB_SIZE - 1);
110   for (p = htab[hash]; p; p = p->next) {
111      if (strcmp(prefix, p->label) == 0) return p->label;
112   }
113
114   p = osnew(pfx);
115   p->label = osstrdup(prefix);
116   p->next = htab[hash];
117   htab[hash] = p;
118
119   return p->label;
120}
121
122static point *
123find_point(const img_point *pt)
124{
125   point *p;
126   for (p = headpoint.next; p != NULL; p = p->next) {
127      if (pt->x == p->p.x && pt->y == p->p.y && pt->z == p->p.z) {
128         return p;
129      }
130   }
131
132   p = osmalloc(ossizeof(point));
133   p->p = *pt;
134   p->X = HUGE_VAL;
135   p->stns = NULL;
136   p->order = 0;
137   p->dir = 0;
138   p->fDone = 0;
139   p->fBroken = 0;
140   p->splays = NULL;
141   p->next = headpoint.next;
142   headpoint.next = p;
143   return p;
144}
145
146static void
147add_leg(point *fr, point *to, const char *prefix, int flags)
148{
149   leg *l;
150   fr->order++;
151   to->order++;
152   l = osmalloc(ossizeof(leg));
153   l->fr = fr;
154   l->to = to;
155   if (prefix)
156      l->prefix = find_prefix(prefix);
157   else
158      l->prefix = NULL;
159   l->next = headleg.next;
160   l->dir = 0;
161   l->fDone = 0;
162   l->broken = 0;
163   l->flags = flags;
164   headleg.next = l;
165}
166
167static void
168add_label(point *p, const char *label, int flags)
169{
170   stn *s = osnew(stn);
171   s->label = osstrdup(label);
172   s->flags = flags;
173   s->next = p->stns;
174   p->stns = s;
175}
176
177/* Read in config file */
178
179
180/* lifted from img.c Should be put somewhere common? JPNP*/
181static char *
182getline_alloc(FILE *fh, size_t ilen)
183{
184   int ch;
185   size_t i = 0;
186   size_t len = ilen;
187   char *buf = xosmalloc(len);
188   if (!buf) return NULL;
189
190   ch = GETC(fh);
191   while (ch != '\n' && ch != '\r' && ch != EOF) {
192      buf[i++] = ch;
193      if (i == len - 1) {
194         char *p;
195         len += len;
196         p = xosrealloc(buf, len);
197         if (!p) {
198            osfree(buf);
199            return NULL;
200         }
201         buf = p;
202      }
203      ch = GETC(fh);
204   }
205   if (ch == '\n' || ch == '\r') {
206      int otherone = ch ^ ('\n' ^ '\r');
207      ch = GETC(fh);
208      /* if it's not the other eol character, put it back */
209      if (ch != otherone) ungetc(ch, fh);
210   }
211   buf[i++] = '\0';
212   return buf;
213}
214
215static int lineno = 0;
216static point *start = NULL;
217
218static char*
219delimword(char *ln, char** lr)
220{
221   char *le;
222
223   while (*ln == ' ' || *ln == '\t' || *ln == '\n' || *ln == '\r')
224      ln++;
225
226   le = ln;
227   while (*le != ' ' && *le != '\t' && *le != '\n' && *le != '\r' && *le != ';' && *le != '\0')
228      le++;
229
230   if (*le == '\0' || *le == ';') {
231      *lr = le;
232   } else {
233      *lr = le + 1;
234   }
235
236   *le = '\0';
237   return ln;
238}
239
240static void
241parseconfigline(const char *fnm, char *ln)
242{
243   point *p;
244   const stn *s;
245   const stn *t;
246   leg *l;
247   char *lc = NULL;
248
249   ln = delimword(ln, &lc);
250
251   if (*ln == '\0') return;
252
253   if (strcmp(ln, "*start")==0) {
254      ln = delimword(lc, &lc);
255      if (*ln == 0)
256         /* TRANSLATORS: Here "station" is a survey station, not a train station. */
257         fatalerror_in_file(fnm, lineno, /*Expecting station name*/28);
258      for (p = headpoint.next; p != NULL; p = p->next) {
259         for (s = p->stns; s; s = s->next) {
260            if (strcmp(s->label, ln)==0) {
261               start = p;
262               /* TRANSLATORS: for extend: "extend" is starting to produce an extended elevation from station %s */
263               printf(msg(/*Starting from station %s*/512),ln);
264               putnl();
265               goto loopend;
266            }
267         }
268      }
269      /* TRANSLATORS: for extend: the user specified breaking a loop or
270       * changing extend direction at this station, but we didn’t find it in
271       * the 3d file */
272      warning_in_file(fnm, lineno, /*Failed to find station %s*/510, ln);
273   } else if (strcmp(ln, "*eleft")==0) {
274      char *ll = delimword(lc, &lc);
275      if (*ll == 0)
276         fatalerror_in_file(fnm, lineno, /*Expecting station name*/28);
277      ln = delimword(lc, &lc);
278      if (*ln == 0) {
279         /* One argument - look for station to switch at. */
280         for (p = headpoint.next; p != NULL; p = p->next) {
281            for (s = p->stns; s; s = s->next) {
282               if (strcmp(s->label, ll)==0) {
283                  /* TRANSLATORS: for extend: */
284                  printf(msg(/*Extending to the left from station %s*/513), ll);
285                  putnl();
286                  p->dir = ELEFT;
287                  goto loopend;
288               }
289            }
290         }
291         warning_in_file(fnm, lineno, /*Failed to find station %s*/510, ll);
292      } else {
293         /* Two arguments - look for a specified leg. */
294         for (l = headleg.next; l; l=l->next) {
295            point * fr = l->fr;
296            point * to = l->to;
297            if (fr && to) {
298               for (s=fr->stns; s; s=s->next) {
299                  int b = 0;
300                  if (strcmp(s->label,ll)==0 || (strcmp(s->label, ln)==0 && (b = 1)) ) {
301                     char * lr = (b ? ll : ln);
302                     for (t=to->stns; t; t=t->next) {
303                        if (strcmp(t->label,lr)==0) {
304                           /* TRANSLATORS: for extend: */
305                           printf(msg(/*Extending to the left from leg %s → %s*/515), s->label, t->label);
306                           putnl();
307                           l->dir = ELEFT;
308                           goto loopend;
309                        }
310                     }
311                  }
312               }
313            }
314         }
315         /* TRANSLATORS: for extend: the user specified breaking a loop or
316          * changing extend direction at this leg, but we didn’t find it in the
317          * 3d file */
318         warning_in_file(fnm, lineno, /*Failed to find leg %s → %s*/511, ll, ln);
319      }
320   } else if (strcmp(ln, "*eright")==0) {
321      char *ll = delimword(lc, &lc);
322      if (*ll == 0)
323         fatalerror_in_file(fnm, lineno, /*Expecting station name*/28);
324      ln = delimword(lc, &lc);
325      if (*ln == 0) {
326         /* One argument - look for station to switch at. */
327         for (p = headpoint.next; p != NULL; p = p->next) {
328            for (s = p->stns; s; s = s->next) {
329               if (strcmp(s->label, ll)==0) {
330                  /* TRANSLATORS: for extend: */
331                  printf(msg(/*Extending to the right from station %s*/514), ll);
332                  putnl();
333                  p->dir = ERIGHT;
334                  goto loopend;
335               }
336            }
337         }
338         warning_in_file(fnm, lineno, /*Failed to find station %s*/510, ll);
339      } else {
340         /* Two arguments - look for a specified leg. */
341         for (l = headleg.next; l; l=l->next) {
342            point * fr = l->fr;
343            point * to = l->to;
344            if (fr && to) {
345               for (s=fr->stns; s; s=s->next) {
346                  int b = 0;
347                  if (strcmp(s->label,ll)==0 || (strcmp(s->label, ln)==0 && (b = 1)) ) {
348                     char * lr = (b ? ll : ln);
349                     for (t=to->stns; t; t=t->next) {
350                        if (strcmp(t->label,lr)==0) {
351                           /* TRANSLATORS: for extend: */
352                           printf(msg(/*Extending to the right from leg %s → %s*/516), s->label, t->label);
353                           putnl();
354                           l->dir=ERIGHT;
355                           goto loopend;
356                        }
357                     }
358                  }
359               }
360            }
361         }
362         warning_in_file(fnm, lineno, /*Failed to find leg %s → %s*/511, ll, ln);
363      }
364   } else if (strcmp(ln, "*eswap")==0) {
365      char *ll = delimword(lc, &lc);
366      if (*ll == 0)
367         fatalerror_in_file(fnm, lineno, /*Expecting station name*/28);
368      ln = delimword(lc, &lc);
369      if (*ln == 0) {
370         /* One argument - look for station to switch at. */
371         for (p = headpoint.next; p != NULL; p = p->next) {
372            for (s = p->stns; s; s = s->next) {
373               if (strcmp(s->label, ll)==0) {
374                  /* TRANSLATORS: for extend: */
375                  printf(msg(/*Swapping extend direction from station %s*/519),ll);
376                  putnl();
377                  p->dir = ESWAP;
378                  goto loopend;
379               }
380            }
381         }
382         warning_in_file(fnm, lineno, /*Failed to find station %s*/510, ll);
383      } else {
384         /* Two arguments - look for a specified leg. */
385         for (l = headleg.next; l; l=l->next) {
386            point * fr = l->fr;
387            point * to = l->to;
388            if (fr && to) {
389               for (s=fr->stns; s; s=s->next) {
390                  int b = 0;
391                  if (strcmp(s->label,ll)==0 || (strcmp(s->label, ln)==0 && (b = 1)) ) {
392                     char * lr = (b ? ll : ln);
393                     for (t=to->stns; t; t=t->next) {
394                        if (strcmp(t->label,lr)==0) {
395                           /* TRANSLATORS: for extend: */
396                           printf(msg(/*Swapping extend direction from leg %s → %s*/520), s->label, t->label);
397                           putnl();
398                           l->dir = ESWAP;
399                           goto loopend;
400                        }
401                     }
402                  }
403               }
404            }
405         }
406         warning_in_file(fnm, lineno, /*Failed to find leg %s → %s*/511, ll, ln);
407      }
408   } else if (strcmp(ln, "*break")==0) {
409      char *ll = delimword(lc, &lc);
410      if (*ll == 0)
411         fatalerror_in_file(fnm, lineno, /*Expecting station name*/28);
412      ln = delimword(lc, &lc);
413      if (*ln == 0) {
414         /* One argument - look for specified station to break at. */
415         for (p = headpoint.next; p != NULL; p = p->next) {
416            for (s = p->stns; s; s = s->next) {
417               if (strcmp(s->label, ll)==0) {
418                  /* TRANSLATORS: for extend: */
419                  printf(msg(/*Breaking survey loop at station %s*/517), ll);
420                  putnl();
421                  p->fBroken = 1;
422                  goto loopend;
423               }
424            }
425         }
426         warning_in_file(fnm, lineno, /*Failed to find station %s*/510, ll);
427      } else {
428         /* Two arguments - look for specified leg and disconnect it at the
429          * first station. */
430         for (l = headleg.next; l; l=l->next) {
431            point * fr = l->fr;
432            point * to = l->to;
433            if (fr && to) {
434               for (s=fr->stns; s; s=s->next) {
435                  int b = 0;
436                  if (strcmp(s->label,ll)==0 || (strcmp(s->label, ln)==0 && (b = 1)) ) {
437                     char * lr = (b ? ll : ln);
438                     for (t=to->stns; t; t=t->next) {
439                        if (strcmp(t->label,lr)==0) {
440                           /* TRANSLATORS: for extend: */
441                           printf(msg(/*Breaking survey loop at leg %s → %s*/518), s->label, t->label);
442                           putnl();
443                           l->broken = (b ? BREAK_TO : BREAK_FR);
444                           goto loopend;
445                        }
446                     }
447                  }
448               }
449            }
450         }
451         warning_in_file(fnm, lineno, /*Failed to find leg %s → %s*/511, ll, ln);
452      }
453   } else {
454      fatalerror_in_file(fnm, lineno, /*Unknown command “%s”*/12, ln);
455   }
456 loopend:
457   ln = delimword(lc, &lc);
458   if (*ln != 0) {
459      fatalerror_in_file(fnm, lineno, /*End of line not blank*/15);
460      /* FIXME: give ln as context? */
461   }
462}
463
464static const struct option long_opts[] = {
465   /* const char *name; int has_arg (0 no_argument, 1 required_*, 2 optional_*); int *flag; int val; */
466   {"survey", required_argument, 0, 's'},
467   {"specfile", required_argument, 0, 'p'},
468   {"show-breaks", no_argument, 0, 'b' },
469   {"help", no_argument, 0, HLP_HELP},
470   {"version", no_argument, 0, HLP_VERSION},
471   {0, 0, 0, 0}
472};
473
474#define short_opts "s:p:b"
475
476static struct help_msg help[] = {
477/*                              <-- */
478   {HLP_ENCODELONG(0),        /*only load the sub-survey with this prefix*/199, 0},
479   /* TRANSLATORS: --help output for extend --specfile option */
480   {HLP_ENCODELONG(1),        /*.espec file to control extending*/90, 0},
481   /* TRANSLATORS: --help output for extend --show-breaks option */
482   {HLP_ENCODELONG(2),        /*show breaks with surface survey legs in output*/91, 0},
483   {0, 0, 0}
484};
485
486static point *
487pick_start_stn(void)
488{
489   point * best = NULL;
490   double zMax = -DBL_MAX;
491   point *p;
492
493   /* Start at the highest entrance with some legs attached. */
494   for (p = headpoint.next; p != NULL; p = p->next) {
495      if (p->order > 0 && p->p.z > zMax) {
496         const stn *s;
497         for (s = p->stns; s; s = s->next) {
498            if (s->flags & img_SFLAG_ENTRANCE) {
499               zMax = p->p.z;
500               return p;
501            }
502         }
503      }
504   }
505   if (best) return best;
506
507   /* If no entrances with legs, start at the highest 1-node. */
508   for (p = headpoint.next; p != NULL; p = p->next) {
509      if (p->order == 1 && p->p.z > zMax) {
510         best = p;
511         zMax = p->p.z;
512      }
513   }
514   if (best) return best;
515
516   /* of course we may have no 1-nodes... */
517   for (p = headpoint.next; p != NULL; p = p->next) {
518      if (p->order != 0 && p->p.z > zMax) {
519         best = p;
520         zMax = p->p.z;
521      }
522   }
523   if (best) return best;
524
525   /* There are no legs - just pick the highest station... */
526   for (p = headpoint.next; p != NULL; p = p->next) {
527      if (p->p.z > zMax) {
528         best = p;
529         zMax = p->p.z;
530      }
531   }
532   return best;
533}
534
535int
536main(int argc, char **argv)
537{
538   const char *fnm_in, *fnm_out;
539   char *desc;
540   img_point pt;
541   int result;
542   point *fr = NULL, *to;
543   const char *survey = NULL;
544   const char *specfile = NULL;
545   img *pimg;
546   int xsections = 0, splays = 0;
547
548   msg_init(argv);
549
550   /* TRANSLATORS: Part of extend --help */
551   cmdline_set_syntax_message(/*INPUT_3D_FILE [OUTPUT_3D_FILE]*/267, 0, NULL);
552   cmdline_init(argc, argv, short_opts, long_opts, NULL, help, 1, 2);
553   while (1) {
554      int opt = cmdline_getopt();
555      if (opt == EOF) break;
556      switch (opt) {
557         case 'b':
558            show_breaks = 1;
559            break;
560         case 's':
561            survey = optarg;
562            break;
563         case 'p':
564            specfile = optarg;
565            break;
566      }
567   }
568   fnm_in = argv[optind++];
569   if (argv[optind]) {
570      fnm_out = argv[optind];
571   } else {
572      char * base_in = base_from_fnm(fnm_in);
573      char * base_out = osmalloc(strlen(base_in) + 8);
574      strcpy(base_out, base_in);
575      strcat(base_out, "_extend");
576      fnm_out = add_ext(base_out, EXT_SVX_3D);
577      osfree(base_in);
578      osfree(base_out);
579   }
580
581   /* try to open image file, and check it has correct header */
582   pimg = img_open_survey(fnm_in, survey);
583   if (pimg == NULL) fatalerror(img_error2msg(img_error()), fnm_in);
584
585   putnl();
586   puts(msg(/*Reading in data - please wait…*/105));
587
588   htab = osmalloc(ossizeof(pfx*) * HTAB_SIZE);
589   {
590       int i;
591       for (i = 0; i < HTAB_SIZE; ++i) htab[i] = NULL;
592   }
593
594   do {
595      result = img_read_item(pimg, &pt);
596      switch (result) {
597      case img_MOVE:
598         fr = find_point(&pt);
599         break;
600      case img_LINE:
601         if (!fr) {
602            result = img_BAD;
603            break;
604         }
605         to = find_point(&pt);
606         if (!(pimg->flags & img_FLAG_SURFACE)) {
607            if (pimg->flags & img_FLAG_SPLAY) {
608               ++splays;
609            } else {
610               add_leg(fr, to, pimg->label, pimg->flags);
611            }
612         }
613         fr = to;
614         break;
615      case img_LABEL:
616         to = find_point(&pt);
617         add_label(to, pimg->label, pimg->flags);
618         break;
619      case img_BAD:
620         (void)img_close(pimg);
621         fatalerror(img_error2msg(img_error()), fnm_in);
622         break;
623      case img_XSECT:
624      case img_XSECT_END:
625         ++xsections;
626         break;
627      }
628   } while (result != img_STOP);
629
630   if (splays) {
631      img_rewind(pimg);
632      fr = NULL;
633      do {
634         result = img_read_item(pimg, &pt);
635         switch (result) {
636         case img_MOVE:
637            fr = find_point(&pt);
638            break;
639         case img_LINE:
640            if (!fr) {
641               result = img_BAD;
642               break;
643            }
644            to = find_point(&pt);
645            if (!(pimg->flags & img_FLAG_SURFACE)) {
646               if (pimg->flags & img_FLAG_SPLAY) {
647                  splay *sp = osmalloc(ossizeof(splay));
648                  --splays;
649                  if (fr->order) {
650                     if (to->order == 0) {
651                        sp->pt = to;
652                        sp->next = fr->splays;
653                        fr->splays = sp;
654                     } else {
655                        printf("Splay without a dead end from %s to %s\n", fr->stns->label, to->stns->label);
656                        osfree(sp);
657                     }
658                  } else if (to->order) {
659                     sp->pt = fr;
660                     sp->next = to->splays;
661                     to->splays = sp;
662                  } else {
663                     printf("Isolated splay from %s to %s\n", fr->stns->label, to->stns->label);
664                     osfree(sp);
665                  }
666               }
667            }
668            fr = to;
669            break;
670         }
671      } while (splays && result != img_STOP);
672   }
673
674   desc = osstrdup(pimg->title);
675
676   if (specfile) {
677      FILE *fs = NULL;
678      char *fnm_used;
679      /* TRANSLATORS: for extend: */
680      printf(msg(/*Applying specfile: “%s”*/521), specfile);
681      putnl();
682      fs = fopenWithPthAndExt("", specfile, NULL, "r", &fnm_used);
683      if (fs == NULL) fatalerror(/*Couldn’t open file “%s”*/24, specfile);
684      while (!feof(fs)) {
685         char *lbuf = getline_alloc(fs, 32);
686         lineno++;
687         if (!lbuf)
688            fatalerror_in_file(fnm_used, lineno, /*Error reading file*/18);
689         parseconfigline(fnm_used, lbuf);
690         osfree(lbuf);
691      }
692      osfree(fnm_used);
693   }
694
695   if (start == NULL) {
696      /* *start wasn't specified in specfile. */
697      start = pick_start_stn();
698      if (!start) fatalerror(/*No survey data*/43);
699   }
700
701   /* TRANSLATORS: for extend:
702    * Used to tell the user that a file is being written - %s is the filename
703    */
704   printf(msg(/*Writing %s…*/522), fnm_out);
705   putnl();
706   pimg_out = img_open_write(fnm_out, desc, img_FFLAG_EXTENDED);
707
708   /* Only does single connected component currently. */
709   do_stn(start, 0.0, NULL, ERIGHT, 0, 0.0, 0.0);
710
711   if (xsections) {
712      img_rewind(pimg);
713      /* Read ahead on pimg before writing pimg_out so we find out if an
714       * img_XSECT_END comes next. */
715      char * label = NULL;
716      int flags = 0;
717      do {
718         result = img_read_item(pimg, &pt);
719         if (result != img_XSECT && result != img_XSECT_END)
720            continue;
721         --xsections;
722         if (label) {
723            if (result == img_XSECT_END)
724               flags |= img_XFLAG_END;
725            img_write_item(pimg_out, img_XSECT, flags, label, 0, 0, 0);
726            osfree(label);
727            label = NULL;
728         }
729         if (result == img_XSECT) {
730            label = osstrdup(pimg->label);
731            flags = pimg->flags;
732            pimg_out->l = pimg->l;
733            pimg_out->r = pimg->r;
734            pimg_out->u = pimg->u;
735            pimg_out->d = pimg->d;
736         }
737      } while (xsections && result != img_STOP);
738   }
739
740   (void)img_close(pimg);
741
742   if (!img_close(pimg_out)) {
743      (void)remove(fnm_out);
744      fatalerror(img_error2msg(img_error()), fnm_out);
745   }
746
747   return EXIT_SUCCESS;
748}
749
750static int adjust_direction(int dir, int by) {
751    if (by == ESWAP)
752        return dir ^ (ELEFT|ERIGHT);
753    if (by)
754        return by;
755    return dir;
756}
757
758static void
759do_splays(point *p, double X, int dir, double tdx, double tdy)
760{
761   const splay *sp;
762   double a;
763   double C, S;
764
765   if (!p->splays) return;
766
767   if (tdx == 0 && tdy == 0) {
768       /* Two adjacent plumbs, or a pair of legs that exactly cancel. */
769       return;
770   }
771
772   /* Bearing in radians. */
773   a = atan2(tdx, tdy);
774   if (dir == ELEFT) {
775       a = -M_PI_2 - a;
776   } else {
777       a = M_PI_2 - a;
778   }
779   C = cos(a);
780   S = sin(a);
781   for (sp = p->splays; sp; sp = sp->next) {
782      double x = X;
783      double z = p->p.z;
784      img_write_item(pimg_out, img_MOVE, 0, NULL, x, 0, z);
785
786      double dx = sp->pt->p.x - p->p.x;
787      double dy = sp->pt->p.y - p->p.y;
788      double dz = sp->pt->p.z - p->p.z;
789
790      double tmp = dx * C + dy * S;
791      dy = dy * C - dx * S;
792      dx = tmp;
793
794      img_write_item(pimg_out, img_LINE, img_FLAG_SPLAY, NULL, x + dx, dy, z + dz);
795   }
796   p->splays = NULL;
797}
798
799static void
800do_stn(point *p, double X, const char *prefix, int dir, int labOnly,
801       double odx, double ody)
802{
803   leg *l, *lp;
804   double dX;
805   const stn *s;
806   int odir = dir;
807   int try_all;
808   int order = p->order;
809
810   for (s = p->stns; s; s = s->next) {
811      img_write_item(pimg_out, img_LABEL, s->flags, s->label, X, 0, p->p.z);
812   }
813
814   if (show_breaks && p->X != HUGE_VAL && p->X != X) {
815      /* Draw "surface" leg between broken stations. */
816      img_write_item(pimg_out, img_MOVE, 0, NULL, p->X, 0, p->p.z);
817      img_write_item(pimg_out, img_LINE, img_FLAG_SURFACE, NULL, X, 0, p->p.z);
818   }
819   p->X = X;
820   if (labOnly || p->fBroken) {
821      return;
822   }
823
824
825   if (order == 0) {
826      /* We've reached a dead end. */
827      do_splays(p, X, dir, odx, ody);
828      return;
829   }
830
831   /* It's better to follow legs along a survey, so make two passes and only
832    * follow legs in the same survey for the first pass.
833    */
834   for (try_all = 0; try_all != 2; ++try_all) {
835      lp = &headleg;
836      for (l = lp->next; l; lp = l, l = lp->next) {
837         dir = odir;
838         if (l->fDone) {
839            /* this case happens iff a recursive call causes the next leg to be
840             * removed, leaving our next pointing to a leg which has been dealt
841             * with... */
842            continue;
843         }
844         if (!try_all && l->prefix != prefix) {
845            continue;
846         }
847         int break_flag;
848         point *p2;
849         if (l->to == p) {
850            break_flag = BREAK_TO;
851            p2 = l->fr;
852         } else if (l->fr == p) {
853            break_flag = BREAK_FR;
854            p2 = l->to;
855         } else {
856            continue;
857         }
858         if (l->broken & break_flag) continue;
859         lp->next = l->next;
860         /* adjust direction of extension if necessary */
861         dir = adjust_direction(dir, p->dir);
862         dir = adjust_direction(dir, l->dir);
863
864         double dx = p2->p.x - p->p.x;
865         double dy = p2->p.y - p->p.y;
866         dX = hypot(dx, dy);
867         double X2 = X;
868         if (dir == ELEFT) {
869            X2 -= dX;
870         } else {
871            X2 += dX;
872         }
873
874         if (p->splays) {
875            do_splays(p, X, dir, odx + dx, ody + dy);
876         }
877
878         img_write_item(pimg_out, img_MOVE, 0, NULL, X, 0, p->p.z);
879         img_write_item(pimg_out, img_LINE, l->flags, l->prefix,
880                        X2, 0, p2->p.z);
881
882         /* We arrive at p2 via a leg, so that's one down right away. */
883         --p2->order;
884
885         l->fDone = 1;
886         /* l->broken doesn't have break_flag set as we checked that above. */
887         do_stn(p2, X2, l->prefix, dir, l->broken, dx, dy);
888         l = lp;
889         if (--order == 0) return;
890      }
891   }
892}
Note: See TracBrowser for help on using the repository browser.