chiark / gitweb /
E annotations work, perhaps need cosmetic tweaks
[trains.git] / layout / redactgraph.c
index dcd5bd783014345f7a4994f8a067f98ec92c9b1d..e2c49f2a5dca384a29a63f5e002be9669a4b4cc7 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * output format from printforforsafety is lines like this:
- *   segment <node>.<side> <node>.<side> <segment>[/<movinfo>]
+ *   segment <node>.<side> <node>.<side> <segment>[/<movinfo>] <distance>
  *   #...         (comment)
  *                (blank)
  *   end          (at end of file, mandatory)
@@ -11,6 +11,7 @@
  *   <movinfo> is  <movfeat><movpos>[<movfeat><movpos>...]*<combpos>
  *            where <movfeat> is alphabetic and <movpos> is and
  *            <combpos> are in decimal and have no unnecessary leading 0's
+ *   <distance> contains only digits and perhaps decimal point
  * semantic restrictions (not enforced by redactgraph but ought to
  * be impossible for layout designer to violate):
  *   Each <segment>[/<movinfo>] appears exactly once.
@@ -21,6 +22,9 @@
  *      the same <segment>
  *    - not at all (indicates a terminus)
  * Refer to safety.h for info regarding <combpos>.
+ *
+ * See layout-data.h comment for info regarding layout data for
+ * control system.
  */
 /* for debugging, runes like
  *  ./ours.redactgraph consistency movfeatsplitedges consistency movfeatrmstubs consistency movfeatsplitnodes consistency trivpairnodes consistency trivnullnodes consistency printforneato | neato -Tps >u.ps
@@ -451,7 +455,7 @@ static int movfeat_isinnernode(Node *node) {
     trace(" not inner: no edges?!\n");
     return 0;
   }
-  trace(" inner %s ",segment->segname);
+  trace(" inner %s ",all_segment->segname);
   return 1;
 }
 
@@ -715,12 +719,118 @@ static void printforforsafety(void) {
        }
        output("*%d", edge->movpos);
       }
-      output("\n");
+      output(" %f\n", edge->distance);
     }
   }
   output("end\n");
 }
 
+static void printforlayoutsegjoins(void) {
+  Node *node;
+  EdgeEnd *edgeend, *edgeend2;
+  Segment **segmentp, *segment, *segment2;
+  int side, side2, order, max_order, colour, any_left;
+  
+  /* we format segment->u as follows: */
+#define LSJ_U_VERTEXORDER_MASK 0x000000ff
+#define LSJ_U_COLOUR_SHIFT                8
+#define LSJ_U_COLOUR_BITS                 16
+#define LSJ_U_COLOUR_UNIT                 (1<<LSJ_U_COLOUR_SHIFT)
+#define LSJ_U_COLOUR_MASK      0x00ffff00
+#define LSJ_U_SEGEND_DONE      0x01000000
+#define LSJ_U_COLOUR_CLASH     0x02000000
+
+  max_order= 0;
+  FOR_ALL_SEGMENTS(segmentp,segment)
+    segment->u= 0;
+  
+  FOR_ALL_NODES(node) {
+    output("layer ");
+    FOR_BOTH(side)
+      if (!node->sides[side].head) {
+       output("segterminus");
+       goto one_sided;
+      }
+    output("segjoin");
+  one_sided:
+    output("%d\n", (node->layermin + node->layermax)/2);
+
+    output("abs segjoin_%s %f %f %f\n",node->pname,
+          node->x,node->y,node->a);
+    FOR_NODE_EDGEENDS(side,edgeend, node) {
+      segment= edgeend->edge->subseg->segment;
+      if (segment->u & LSJ_U_SEGEND_DONE) continue;
+      segment->u |= LSJ_U_SEGEND_DONE;
+      assert(~segment->u & LSJ_U_VERTEXORDER_MASK); /* detect overflow */
+      segment->u++;
+      order= segment->u & LSJ_U_VERTEXORDER_MASK;
+      if (order > max_order) max_order= order;
+      output("segend segjoin_%s %s\n",node->pname, segment->segname);
+    }
+    output("\n");
+    FOR_ALL_SEGMENTS(segmentp,segment)
+      segment->u &= ~LSJ_U_SEGEND_DONE;
+  }
+
+  /* Welsh and Powell's graph colouring algorithm
+   * (Wikipedia Graph_coloring) */
+  output("# max-order %d\n",max_order);
+
+  for (colour=LSJ_U_COLOUR_UNIT, any_left=1;
+       any_left;
+       colour+=LSJ_U_COLOUR_UNIT) {
+    output("# colour %x\n", colour);
+    assert(!(colour & ~LSJ_U_COLOUR_MASK));
+   something_done:
+    any_left= 0;
+
+    FOR_ALL_SEGMENTS(segmentp,segment)
+      segment->u &= ~LSJ_U_COLOUR_CLASH;
+
+    FOR_ALL_NODES(node)
+      FOR_NODE_EDGEENDS(side,edgeend, node) {
+        segment= edgeend->edge->subseg->segment;
+       if (colour == (segment->u & LSJ_U_COLOUR_MASK)) {
+         output("#  already %s\n", segment->segname);
+         FOR_NODE_EDGEENDS(side2,edgeend2, node) {
+           segment2= edgeend2->edge->subseg->segment;
+           output("#   therefore-not %s\n", segment2->segname);
+           segment2->u |= LSJ_U_COLOUR_CLASH;
+         }
+       }
+      }
+
+    for (order=max_order; order>0; order--) { /* idiot-sort */
+      output("#  order %d\n", order);
+      FOR_ALL_SEGMENTS(segmentp,segment)
+       if ((segment->u & LSJ_U_VERTEXORDER_MASK) == order) {
+         if (segment->u & LSJ_U_COLOUR_MASK) continue;
+         any_left= 1;
+         if (segment->u & LSJ_U_COLOUR_CLASH) {
+           output("#   still-clashes %s\n", segment->segname);
+           continue;
+         }
+         segment->u |= colour;
+         output("#   coloured %s\n", segment->segname);
+         goto something_done;
+       } else {
+         output("# (skip %s %x)\n", segment->segname,segment->u);
+       }
+    }
+  }
+
+  FOR_ALL_SEGMENTS(segmentp,segment) {
+    int tcolour= segment->u & LSJ_U_COLOUR_MASK;
+    const double val1=0.75, val2=0.50;
+    double value;
+    if (!tcolour) continue;
+    value= val1 +
+            (tcolour - LSJ_U_COLOUR_UNIT*2) * (val1-val2) /
+            (colour - LSJ_U_COLOUR_UNIT*2);
+    output("segcmap %s  %f setgray\n", segment->segname,value);
+  }
+}
+
 /*---------- main program ----------*/
 
 typedef struct {
@@ -732,6 +842,7 @@ static const OpInfo opinfos[]= {
 #define OI(x) { #x, x },
   OI(printforneato)
   OI(printforforsafety)
+  OI(printforlayoutsegjoins)
   OI(consistency)
   OI(movfeatsplitedges)
   OI(movfeatrmstubs)