chiark / gitweb /
Further cleanup of skeleton paths.
authorBen Harris <bjh21@bjh21.me.uk>
Mon, 17 Jul 2017 23:14:20 +0000 (00:14 +0100)
committerBen Harris <bjh21@bjh21.me.uk>
Mon, 17 Jul 2017 23:14:20 +0000 (00:14 +0100)
The cleanup itself is good, but emit_paths() will need enhancement.
At the moment, it assumes that all paths are closed, so it doesn't
matter where on a path it starts emitting it.  With an open path,
though, it's important to emit it starting at one end, so there will
have to be a mechanism for distinguishing open from closed paths and
behaving accordingly.

bedstead.c

index f47f521b43324328798e43f412208a27125f8909..8499a66238b162955e0056e618df3d8832d62fa6 100644 (file)
@@ -1898,10 +1898,34 @@ dochar(char const data[YSIZE], unsigned flags)
        emit_path();
 }
 
+static void
+reverse_path(point *a)
+{
+       point *tmp;
+       
+       while (a->prev != NULL)
+               a = a->prev;
+       while (a != NULL) {
+               tmp = a->next;
+               a->next = a->prev;
+               a->prev = tmp;
+               a = tmp;
+       }
+}              
+
 /* Join together two points each at the end of a path */
 static void
 join_ends(point *a, point *b)
 {
+       point *tmp;
+
+       if (a->prev == NULL && b->next == NULL) {
+               tmp = a; a = b; b = tmp;
+       }
+       if (a->prev == NULL)
+               reverse_path(a);
+       if (b->next == NULL)
+               reverse_path(b);
        assert(a->next == NULL);
        assert(a->prev != NULL);
        assert(b->prev == NULL);
@@ -1910,7 +1934,7 @@ join_ends(point *a, point *b)
        a->next = b;
        b->prev = a;
        fix_identical(a); /* Will delete a */
-       fix_collinear(b); /* Will delete b */
+       fix_collinear(b); /* Might delete b */
 }
 
 static bool
@@ -1919,23 +1943,44 @@ point_endp(point *p)
        return p->next == NULL || p->prev == NULL;
 }
 
+static bool
+point_deadp(point *p)
+{
+       return p->next == NULL && p->prev == NULL;
+}
+
 static void
 clean_skeleton()
 {
        int i, j;
 
+       /* Pass 1: join collinear connected segments */
        for (i = 0; i < nextpoint; i++) {
-               if (points[i].prev == NULL && points[i].next == NULL)
+               if (point_deadp(&points[i]))
                        continue;
                for (j = 0; j < nextpoint; j++) {
-                       if (points[j].prev == NULL && points[j].next == NULL)
+                       if (point_deadp(&points[j]))
                                continue;
                        if (vec_eqp(points[i].v, points[j].v) &&
                            points[i].next == NULL && points[j].prev == NULL &&
                            vec_inline3(points[i].prev->v, points[i].v,
                                        points[j].next->v))
                                join_ends(&points[i], &points[j]);
-                       if (points[i].prev == NULL && points[i].next == NULL)
+                       if (point_deadp(&points[i]))
+                               break;
+               }
+       }
+       /* Pass 2: join any connected segments */
+       for (i = 0; i < nextpoint; i++) {
+               if (point_deadp(&points[i]))
+                       continue;
+               for (j = i+1; j < nextpoint; j++) {
+                       if (point_deadp(&points[j]))
+                               continue;
+                       if (vec_eqp(points[i].v, points[j].v) &&
+                           point_endp(&points[i]) && point_endp(&points[j]))
+                               join_ends(&points[i], &points[j]);
+                       if (point_deadp(&points[i]))
                                break;
                }
        }