PATCH: extending extend

John Pybus john at pybus.org
Thu Dec 9 16:31:55 GMT 2004


Hi Olly,

I've recently been using extend to create extended elevations of OUCC 
caves and needed something a bit more capable to cope with more complex 
sections of cave.

The attached patch provides the ability to switch the direction of 
extension between left and right, to explicitly specify the start 
station, and to break the extension at particular stations or legs.  It 
adds an option to specify a specfile which contains directives in an svx 
like syntax such as follows:

;This is a comment

*start entrance.0 ;this is a comment too

; start extending leftwards from station half-way-down.5
*eleft half-way-down.5

; switch back to extending to the right
*eright further-down.8

; extend left from further-down.junction, but only
; the leg joining it to very-deep.1, other legs continuing
; as before
*eleft further-down.junction  very-deep.1

; break the survey at station side-loop.4
*break side-loop.4

; break survey at side-loop.junction only
; for leg going to complex-loop.2
*break side-loop.junction complex-loop.2

==================

The directives need not be in order though the last *start or 
*eleft/*eright for a particular station/leg will take precedence, and 
directives which identify a leg override those specifying only a station.

It's not as easy to use as an interactive system would be, and may be to 
too cumbersome for complex systems, but it meets the needs of somewhat 
larger and more complicated caves than the current version.

The patch is against the 1.0 cvs HEAD; hopefully it can go into the next 
survex release.

Cheers,

John
-------------- next part --------------
Index: lib/messages.txt
===================================================================
RCS file: /usr/data/cvs/survex/lib/messages.txt,v
retrieving revision 1.179
diff -U3 -r1.179 messages.txt
--- lib/messages.txt	1 Oct 2004 18:54:27 -0000	1.179
+++ lib/messages.txt	9 Dec 2004 11:54:13 -0000
@@ -3536,6 +3536,37 @@
 sk:502 Zrušené: %s
 ro:502 Eliminat: %s
 #
+# for extend:
+en:600 Don't understand command `%s' in config, line %i
+#
+en:601 Unexpected content `%s' in config, line %i
+#
+en:602 Command without station name in config, line %i
+#
+en:603 Failed to find station %s in config, line %i
+#
+en:604 Starting from station %s
+#
+en:605 Plotting to the left from station %s
+#
+en:606 Failed to find leg %s -> %s in config, line %i
+#
+en:607 Plotting to the left from leg %s -> %s
+#
+en:608 Plotting to the right from station %s
+#
+en:609 Plotting to the right from leg %s -> %s
+#
+en:610 Breaking survey at station %s
+#
+en:611 Breaking survey at leg %s -> %s
+#
+en:612 Error reading line %i from spec file
+#
+en:613 Applying specfile: `%s'
+#
+en:614 Writing out .3d file...
+#
 # "don't extract" messages - these are compiled into the programs
 #
 en:1000 Can't open message file `%s' using path `%s'
Index: src/extend.c
===================================================================
RCS file: /usr/data/cvs/survex/src/extend.c,v
retrieving revision 1.45
diff -U3 -r1.45 extend.c
--- src/extend.c	22 Nov 2003 00:19:26 -0000	1.45
+++ src/extend.c	9 Dec 2004 11:54:14 -0000
@@ -48,24 +48,36 @@
    img_point p;
    const stn *stns;
    unsigned int order;
+   int fDir;
+   int fDone;
    struct POINT *next;
 } point;
 
 typedef struct LEG {
    point *fr, *to;
    const char *prefix;
+   int fDir;
    int fDone;
    int flags;
    struct LEG *next;
 } leg;
 
-static point headpoint = {{0, 0, 0}, NULL, 0, NULL};
+#define DONE        0x01
+#define BREAK_FR    0x04
+#define BREAK_TO    0x08
+#define BREAK       (BREAK_FR | BREAK_TO)
+
+
+#define ELEFT  0x04
+#define ERIGHT 0x08
 
-static leg headleg = {NULL, NULL, NULL, 1, 0, NULL};
+static point headpoint = {{0, 0, 0}, NULL, 0, 0, 0, NULL};
+
+static leg headleg = {NULL, NULL, NULL, 0, 0, 0, NULL};
 
 static img *pimg;
 
-static void do_stn(point *, double, const char *);
+static void do_stn(point *, double, const char *, int);
 
 typedef struct pfx {
    const char *label;
@@ -111,6 +123,8 @@
    p->p = *pt;
    p->stns = NULL;
    p->order = 0;
+   p->fDir = 0;
+   p->fDone = 0;
    p->next = headpoint.next;
    headpoint.next = p;
    return p;
@@ -130,6 +144,7 @@
    else
       l->prefix = NULL;
    l->next = headleg.next;
+   l->fDir = 0;
    l->fDone = 0;
    l->flags = flags;
    headleg.next = l;
@@ -145,19 +160,238 @@
    p->stns = s;
 }
 
+/* Read in config file */
+
+
+/* lifted from img.c Should be put somewhere common? JPNP*/
+static char *
+getline_alloc(FILE *fh, size_t ilen)
+{
+   int ch;
+   size_t i = 0;
+   size_t len = ilen;
+   char *buf = xosmalloc(len);
+   if (!buf) return NULL;
+
+   ch = getc(fh);
+   while (ch != '\n' && ch != '\r' && ch != EOF) {
+      buf[i++] = ch;
+      if (i == len - 1) {
+	 char *p;
+	 len += len;
+	 p = xosrealloc(buf, len);
+	 if (!p) {
+	    osfree(buf);
+	    return NULL;
+	 }
+	 buf = p;
+      }
+      ch = getc(fh);
+   }
+   if (ch == '\n' || ch == '\r') {
+      int otherone = ch ^ ('\n' ^ '\r');
+      ch = getc(fh);
+      /* if it's not the other eol character, put it back */
+      if (ch != otherone) ungetc(ch, fh);
+   }
+   buf[i++] = '\0';
+   return buf;
+}
+
+int lineno = 0;
+point *start = NULL;
+
+static char*
+delimword(char *ln, char** lr)
+{
+   char *le;
+
+   while (*ln == ' ' || *ln == '\t' || *ln == '\n' || *ln == '\r')
+      ln++;
+
+   le = ln;
+   while (*le != ' ' && *le != '\t' && *le != '\n' && *le != '\r' && *le != ';' && *le != '\0')
+      le++;
+
+   if (*le == '\0' || *le == ';') {
+      *lr = le;
+   } else {
+      *lr = le + 1;
+   }
+   
+   *le = '\0';
+   return ln;
+}
+
+static void
+parseconfigline(char *ln)
+{
+   point *p;
+   const stn *s;
+   const stn *t;
+   leg *l;
+   char *lc = NULL;
+
+   ln = delimword(ln, &lc);
+
+   if (*ln == '\0') return;
+
+   if (strcmp(ln, "*start")==0) {
+      ln = delimword(lc, &lc);
+      if (*ln == 0) fatalerror(/*Command without station name in config, line %i*/602, lineno);
+      for (p = headpoint.next; p != NULL; p = p->next) {
+	 for (s = p->stns; s; s = s->next) {
+	    if (strcmp(s->label, ln)==0) {
+	       start = p;
+	       printf(msg(/*Starting from station %s*/604),ln);
+	       putnl();
+	       goto loopend;
+	    }
+	 }
+      }
+      warning(/*Failed to find station %s in config, line %i*/603, ln, lineno);
+   } else if (strcmp(ln, "*eleft")==0) {
+      char *ll = delimword(lc, &lc);
+      if (*ll == 0) fatalerror(/*Command without station name in config, line %i*/602,lineno);
+      ln = delimword(lc, &lc);
+      if (*ln == 0) { /* One argument, look for point to switch at. */
+	 for (p = headpoint.next; p != NULL; p = p->next) {
+	    for (s = p->stns; s; s = s->next) {
+	       if (strcmp(s->label, ll)==0) {
+		  printf(msg(/*Plotting to the left from station %s*/605),ll);
+		  putnl();
+		  p->fDir = ELEFT;
+		  goto loopend;
+	       }
+	    }
+	 }
+	 warning(/*Failed to find station %s in config, line %i*/603, ll, lineno);       
+      } else { /* Two arguments look for a specific leg */
+	 for (l = headleg.next; l; l=l->next) {
+	    point * fr = l->fr;
+	    point * to = l->to;
+	    if (fr && to) {
+	       for (s=fr->stns; s; s=s->next) {
+		  int b = 0;
+		  if (strcmp(s->label,ll)==0 || (strcmp(s->label, ln)==0 && (b = 1)) ) {
+		     char * lr = (b ? ll : ln);
+		     for (t=to->stns; t; t=t->next) {
+			if (strcmp(t->label,lr)==0) {
+			   printf(msg(/*Plotting to the left from leg %s -> %s*/607), s->label, t->label);
+			   putnl();
+			   l->fDir=ELEFT;
+			   goto loopend;
+			}
+		     }
+		  }
+	       }
+	    }
+	 }
+	 warning(/*Failed to find leg %s-%s in config, line %i*/606, ll, ln, lineno);
+      }
+   } else if (strcmp(ln, "*eright")==0) {
+      char *ll = delimword(lc, &lc);
+      if (*ll == 0) fatalerror(/*Command without station name in config, line %i*/602,lineno);
+      ln = delimword(lc, &lc);
+      if (*ln == 0) { /* One argument, look for point to switch at. */
+	 for (p = headpoint.next; p != NULL; p = p->next) {
+	    for (s = p->stns; s; s = s->next) {
+	       if (strcmp(s->label, ll)==0) {
+		  printf(msg(/*Plotting to the right from station %s*/608),ll);
+		  putnl();
+		  p->fDir = ERIGHT;
+		  goto loopend;
+	       }
+	    }
+	 }
+	 warning(/*Failed to find station %s in config, line %i*/603, ll, lineno);      
+      } else { /* Two arguments look for a specific leg */
+	 for (l = headleg.next; l; l=l->next) {
+	    point * fr = l->fr;
+	    point * to = l->to;
+	    if (fr && to) {
+	       for (s=fr->stns; s; s=s->next) {
+		  int b = 0;
+		  if (strcmp(s->label,ll)==0 || (strcmp(s->label, ln)==0 && (b = 1)) ) {
+		     char * lr = (b ? ll : ln);
+		     for (t=to->stns; t; t=t->next) {
+			if (strcmp(t->label,lr)==0) {
+			   printf(msg(/*Plotting to the right from leg %s -> %s*/609), s->label, t->label);
+			   printf("\n");
+			   l->fDir=ERIGHT;
+			   goto loopend;
+			}
+		     }
+		  }
+	       }
+	    }
+	 }
+	 warning(/*Failed to find leg %s-%s in config, line %i*/606, ll, ln, lineno);
+      }
+   } else if (strcmp(ln, "*break")==0) {
+      char *ll = delimword(lc, &lc);
+      if (*ll == 0) fatalerror(/*Command without station name in config, line %i*/602,lineno);
+      ln = delimword(lc, &lc);
+      if (*ln == 0) { /* One argument, look for point to break at. */
+	 for (p = headpoint.next; p != NULL; p = p->next) {
+	    for (s = p->stns; s; s = s->next) {
+	       if (strcmp(s->label, ll)==0) {
+		  printf(msg(/*Breaking survey at station %s*/610), ll);
+		  putnl();
+		  p->fDone = BREAK;
+		  goto loopend;
+	       }
+	    }
+	 }
+	 warning(/*Failed to find station %s in config, line %i*/603, ll, lineno);  
+      } else { /* Two arguments look for a specific leg */
+	 for (l = headleg.next; l; l=l->next) {
+	    point * fr = l->fr;
+	    point * to = l->to;
+	    if (fr && to ) {
+	       for (s=fr->stns; s; s=s->next) {
+		  int b = 0;
+		  if (strcmp(s->label,ll)==0 || (strcmp(s->label, ln)==0 && (b = 1)) ) {
+		     char * lr = (b ? ll : ln);
+		     for (t=to->stns; t; t=t->next) {
+			if (strcmp(t->label,lr)==0) {
+			   printf(msg(/*Breaking survey at leg %s -> %s*/611), s->label, t->label);
+			   putnl();
+			   l->fDone = (b ? BREAK_TO : BREAK_FR);
+			   goto loopend;
+			}
+		     }
+		  }
+	       }
+	    }
+	 }
+	 warning(/*Failed to find leg %s-%s in config, line %i*/606, ll, ln, lineno);
+      }
+   } else {
+      fatalerror(/*"Don't understand command `%s' in config, line %i"*/600, ln, lineno);
+   }
+ loopend:
+   ln = delimword(lc, &lc);
+   if (*ln != 0) {
+      fatalerror(/*"Unexpected content `%s' in config, line %i"*/601, ln, lineno);
+   }
+}
+
 static const struct option long_opts[] = {
    /* const char *name; int has_arg (0 no_argument, 1 required_*, 2 optional_*); int *flag; int val; */
    {"survey", required_argument, 0, 's'},
+   {"specfile", required_argument, 0, 'p'},
    {"help", no_argument, 0, HLP_HELP},
    {"version", no_argument, 0, HLP_VERSION},
    {0, 0, 0, 0}
 };
 
-#define short_opts "s:"
+#define short_opts "s:p:"
 
 static struct help_msg help[] = {
 /*				<-- */
    {HLP_ENCODELONG(0),          "only load the sub-survey with this prefix"},
+   {HLP_ENCODELONG(1),          "apply specifications from the named file"},
    {0, 0}
 };
 
@@ -170,9 +404,9 @@
    int result;
    point *fr = NULL, *to;
    double zMax = -DBL_MAX;
-   point *start = NULL;
    point *p;
    const char *survey = NULL;
+   const char *specfile = NULL;
 
    msg_init(argv);
 
@@ -182,6 +416,7 @@
       int opt = cmdline_getopt();
       if (opt == EOF) break;
       if (opt == 's') survey = optarg;
+      if (opt == 'p') specfile = optarg;
    }
    fnm_in = argv[optind++];
    if (argv[optind]) {
@@ -235,50 +470,77 @@
 
    (void)img_close(pimg);
 
-   /* start at the highest entrance with some legs attached */
-   for (p = headpoint.next; p != NULL; p = p->next) {
-      if (p->order > 0 && p->p.z > zMax) {
-	 const stn *s;
-	 for (s = p->stns; s; s = s->next) {
-	    if (s->flags & img_SFLAG_ENTRANCE) {
-	       start = p;
-	       zMax = p->p.z;
-	       break;
-	    }
+   if (specfile) {
+      FILE *fs = NULL;
+      printf(msg(/*Applying specfile: `%s'*/613), specfile);
+      putnl();
+      fs = fopenWithPthAndExt("", specfile, NULL, "r", NULL);
+      if (fs == NULL) fatalerror(/*Unable to open file*/93, specfile);
+      while (!feof(fs)) {
+	 char *lbuf = NULL;
+	 lbuf = getline_alloc(fs, 32);
+	 lineno++;
+	 if (lbuf) {
+	    parseconfigline(lbuf);
+	 } else {
+	    error(/*Error reading line %i from spec file*/612, lineno);
+	    osfree(lbuf);
+	    break;
 	 }
+	 osfree(lbuf);
       }
    }
-   if (start == NULL) {
-      /* if no entrances with legs, start at the highest 1-node */
+
+   if (start == NULL) { /* i.e. start wasn't specified in specfile */
+   
+      /* start at the highest entrance with some legs attached */
       for (p = headpoint.next; p != NULL; p = p->next) {
-	 if (p->order == 1 && p->p.z > zMax) {
-	    start = p;
-	    zMax = p->p.z;
+	 if (p->order > 0 && p->p.z > zMax) {
+	    const stn *s;
+	    for (s = p->stns; s; s = s->next) {
+	       if (s->flags & img_SFLAG_ENTRANCE) {
+		  start = p;
+		  zMax = p->p.z;
+		  break;
+	       }
+	    }
 	 }
       }
-      /* of course we may have no 1-nodes... */
       if (start == NULL) {
+	 /* if no entrances with legs, start at the highest 1-node */
 	 for (p = headpoint.next; p != NULL; p = p->next) {
-	    if (p->order != 0 && p->p.z > zMax) {
+	    if (p->order == 1 && p->p.z > zMax) {
 	       start = p;
 	       zMax = p->p.z;
 	    }
 	 }
+	 /* of course we may have no 1-nodes... */
 	 if (start == NULL) {
-	    /* There are no legs - just pick the highest station... */
 	    for (p = headpoint.next; p != NULL; p = p->next) {
-	       if (p->p.z > zMax) {
+	       if (p->order != 0 && p->p.z > zMax) {
 		  start = p;
 		  zMax = p->p.z;
 	       }
 	    }
-	    if (!start) fatalerror(/*No survey data*/43);
+	    if (start == NULL) {
+	       /* There are no legs - just pick the highest station... */
+	       for (p = headpoint.next; p != NULL; p = p->next) {
+		  if (p->p.z > zMax) {
+		     start = p;
+		     zMax = p->p.z;
+		  }
+	       }
+	       if (!start) fatalerror(/*No survey data*/43);
+	    }
 	 }
       }
    }
+
+   printf(msg(/*Writing out .3d file...*/614));
+   putnl();
    pimg = img_open_write(fnm_out, desc, fTrue);
 
-   do_stn(start, 0.0, NULL); /* only does highest connected component currently */
+   do_stn(start, 0.0, NULL, ERIGHT); /* only does single connected component currently */
    if (!img_close(pimg)) {
       (void)remove(fnm_out);
       fatalerror(img_error(), fnm_out);
@@ -288,7 +550,7 @@
 }
 
 static void
-do_stn(point *p, double X, const char *prefix)
+do_stn(point *p, double X, const char *prefix, int dir)
 {
    leg *l, *lp;
    double dX;
@@ -297,62 +559,86 @@
    for (s = p->stns; s; s = s->next) {
       img_write_item(pimg, img_LABEL, s->flags, s->label, X, 0, p->p.z);
    }
+   if (p->fDone & BREAK) {
+     return;
+   }
+
    lp = &headleg;
    for (l = lp->next; l; lp = l, l = lp->next) {
-      if (l->fDone) {
-	 /* this case happens iff a recursive call causes the next leg to be
+      if (l->fDone & DONE) {
+	 /* this case happens if a recursive call causes the next leg to be
 	  * removed, leaving our next pointing to a leg which has been dealt
 	  * with... */
       } else if (l->prefix == prefix) {
 	 if (l->to == p) {
+	    if (l->fDone & BREAK_TO) continue;
 	    lp->next = l->next;
+	    /* adjust direction of extension if necessary */
+	    if (l->to->fDir) dir = l->to->fDir;
+	    if (l->fDir) dir = l->fDir;
+
 	    dX = hypot(l->fr->p.x - l->to->p.x, l->fr->p.y - l->to->p.y);
+	    if (dir == ELEFT) dX *= -1.0;
 	    img_write_item(pimg, img_MOVE, 0, NULL, X + dX, 0, l->fr->p.z);
 	    img_write_item(pimg, img_LINE, l->flags, l->prefix,
 			   X, 0, l->to->p.z);
-	    l->fDone = 1;
-	    do_stn(l->fr, X + dX, l->prefix);
-	    /* osfree(l); */
+	    l->fDone |= DONE;
+	    do_stn(l->fr, X + dX, l->prefix, dir);
 	    l = lp;
 	 } else if (l->fr == p) {
+	    if (l->fDone & BREAK_FR) continue;
 	    lp->next = l->next;
+	    /* adjust direction of extension if necessary */
+            if (l->fr->fDir) dir = l->fr->fDir;
+	    if (l->fDir) dir = l->fDir;
+
 	    dX = hypot(l->fr->p.x - l->to->p.x, l->fr->p.y - l->to->p.y);
+	    if (dir == ELEFT) dX *= -1.0;
 	    img_write_item(pimg, img_MOVE, 0, NULL, X, 0, l->fr->p.z);
 	    img_write_item(pimg, img_LINE, l->flags, l->prefix,
 			   X + dX, 0, l->to->p.z);
-	    l->fDone = 1;
-	    do_stn(l->to, X + dX, l->prefix);
-	    /* osfree(l); */
+	    l->fDone |= DONE;
+	    do_stn(l->to, X + dX, l->prefix, dir);
 	    l = lp;
 	 }
       }
    }
    lp = &headleg;
    for (l = lp->next; l; lp = l, l = lp->next) {
-      if (l->fDone) {
+      if (l->fDone & DONE) {
 	 /* this case happens iff a recursive call causes the next leg to be
 	  * removed, leaving our next pointing to a leg which has been dealt
 	  * with... */
       } else {
 	 if (l->to == p) {
+	    if (l->fDone & BREAK_TO) continue;
 	    lp->next = l->next;
+	    /* adjust direction of extension if necessary */
+	    if (l->to->fDir) dir = l->to->fDir;
+	    if (l->fDir) dir = l->fDir;
+	    
 	    dX = hypot(l->fr->p.x - l->to->p.x, l->fr->p.y - l->to->p.y);
+	    if (dir == ELEFT) dX *= -1.0;
 	    img_write_item(pimg, img_MOVE, 0, NULL, X + dX, 0, l->fr->p.z);
 	    img_write_item(pimg, img_LINE, l->flags, l->prefix,
 			   X, 0, l->to->p.z);
-	    l->fDone = 1;
-	    do_stn(l->fr, X + dX, l->prefix);
-	    /* osfree(l); */
+	    l->fDone |= DONE;
+	    do_stn(l->fr, X + dX, l->prefix, dir);
 	    l = lp;
 	 } else if (l->fr == p) {
+	    if (l->fDone & BREAK_FR) continue;
 	    lp->next = l->next;
+	    /* adjust direction of extension if necessary */
+            if (l->fr->fDir) dir = l->fr->fDir;
+	    if (l->fDir) dir = l->fDir;
+
 	    dX = hypot(l->fr->p.x - l->to->p.x, l->fr->p.y - l->to->p.y);
+	    if (dir == ELEFT) dX *= -1.0;
 	    img_write_item(pimg, img_MOVE, 0, NULL, X, 0, l->fr->p.z);
 	    img_write_item(pimg, img_LINE, l->flags, l->prefix,
 			   X + dX, 0, l->to->p.z);
-	    l->fDone = 1;
-	    do_stn(l->to, X + dX, l->prefix);
-	    /* osfree(l); */
+	    l->fDone |= DONE;
+	    do_stn(l->to, X + dX, l->prefix, dir);
 	    l = lp;
 	 }
       }


More information about the Survex mailing list