From: ian Date: Sun, 20 Mar 2005 17:53:51 +0000 (+0000) Subject: new arrangements for trivia etc., wip for movfeat stuff X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ijackson/git?a=commitdiff_plain;h=249ddcc0584a8782b57ba070d4a3871777b5fbbe;p=trains.git new arrangements for trivia etc., wip for movfeat stuff --- diff --git a/layout/graph-data.h b/layout/graph-data.h index 37b860e..6ecbcad 100644 --- a/layout/graph-data.h +++ b/layout/graph-data.h @@ -64,6 +64,13 @@ extern int next_nodenum, next_edgenum; #define FOR_ALL_NODES(node) for (node=all_nodes.head; node; node=node->next) #define FOR_BOTH(sideend) for (sideend=0; sideend<2; sideend++) +#define FOR_NODE_EDGEENDS(side,edgeend, node) \ + FOR_BOTH(side) \ + FOR_SIDE_EDGEENDS(edgeend, (node),side) + +#define FOR_SIDE_EDGEENDS(edgeend, node,side) \ + for (edgeend=(node)->sides[(side)].head; edgeend; edgeend=edgeend->next) + #define FOR_SEGMENT_MOVFEATS(i,f, segment) \ for (i=0, f=segment->movfeats; i < segment->n_movfeats; i++, f++) @@ -76,11 +83,10 @@ extern int next_nodenum, next_edgenum; * appropriately. edgeend must be of type EdgeEnd*, and side of type * int; these are used as working variables by FOR_EDGES. */ -#define FOR_EDGES(edge, node,side,edgeend) \ - FOR_BOTH(side) \ - for (edgeend=node->sides[side].head; edgeend; edgeend=edgeend->next) \ - if ((edge= edgeend->edge), edgeend->end) { \ - /* do each edge once, from end 0, only */ \ +#define FOR_EDGES(edge, node,side,edgeend) \ + FOR_NODE_EDGEENDS(side,edgeend, node) \ + if ((edge= edgeend->edge), edgeend->end) { \ + /* do each edge once, from end 0, only */ \ } else diff --git a/layout/redactgraph.c b/layout/redactgraph.c index 4ec2e6f..29fa3f6 100644 --- a/layout/redactgraph.c +++ b/layout/redactgraph.c @@ -166,8 +166,8 @@ static int count_edges(const NodeSide *node) { return count; } -static Edge *makeedge(const char *pname, double distance, - MovFeat *subseg, int movpos) { +static Edge *edge_create(const char *pname, double distance, + MovFeat *subseg, int movpos) { Edge *e; int end; @@ -184,6 +184,29 @@ static Edge *makeedge(const char *pname, double distance, return e; } +static Node *node_create(const char *pname) { + Node *n; + int side; + + n= MMALLOC(sizeof(*n)); + n->pname= pname; + FOR_BOTH(side) { + n->sides[side].node= n; + n->sides[side].side= side; + LIST_INIT(n->sides[side]); + } + LIST_LINK_TAIL(all_nodes,n); + return n; +} + +/* Perhaps surprisingly, it's OK to remove nodes and edges in loops + * made with the macros in graph-data.h, provided that if the + * _current_ node or edge is removed, that happens last. This is + * because removing a node or edge it doesn't actually free it or + * change its contents, so the thing->next is still valid afterwards. + * This depends on the fact that we never free anything we're done + * with ! + */ static void edgeend_detach(EdgeEnd *toremove) { trace("[detach:"); trace_edgeend(toremove); @@ -201,9 +224,11 @@ static void edgeend_replumb(EdgeEnd *tomove, NodeSide *newtarget) { edgeend_attach(tomove,newtarget); } -static void edge_delete(Edge *edge) { - edgeend_detach(&edge->ends[0]); - edgeend_detach(&edge->ends[1]); +static void edge_delete(EdgeEnd *detachlast) { + Edge *edge; + edge= detachlast->edge; + edgeend_detach(&edge->ends[!detachlast->end]); + edgeend_detach(detachlast); trace("[delete:"); trace_edge(edge); trace("]"); } @@ -230,7 +255,7 @@ static void node_surely_orphaned(Node *node) { * * The conversion has two stages: * - * FIRST STAGE (movfeatmultedges): + * FIRST STAGE (movfeatsplitedges): * * We multiply up each edge of any segment with moveable features to * be an edge which is a position of the *-feature. @@ -248,7 +273,7 @@ static void node_surely_orphaned(Node *node) { * *----A1/P0----* becomes *----A1/P0J0----* * `---A1/P0J1---' * - * SECOND STAGE: + * SECOND STAGE (movfeatrmstubs): * * We remove stub moveable edges: whenever, at a node which has only * edges which are part of the same segment, we find an edge on one @@ -290,7 +315,7 @@ static void node_surely_orphaned(Node *node) { * `---A1/P1J0----*---A1/P1J1--' */ -static void movfeatmultedges(void) { +static void movfeatsplitedges(void) { Node *node; int side, l, i, weight, combpos, end; EdgeEnd *edgeend; @@ -299,13 +324,13 @@ static void movfeatmultedges(void) { MovFeat *subseg, *starfeature, *loopfeat; char *featstr; - trace("movfeatmultedges ...\n"); + trace("movfeatsplitedges ...\n"); FOR_ALL_NODES(node) { FOR_EDGES(edge, node,side,edgeend) { subseg= edge->subseg; segment= subseg->segment; - trace("movfeatmultedges "); trace_edge(edge); + trace("movfeatsplitedges "); trace_edge(edge); trace(" segment %s ", segment->segname); if (segment->n_movfeats<=1) { trace("no moveables\n"); continue; } if (subseg == segment->starfeature) { trace("*-feature\n"); continue; } @@ -354,41 +379,130 @@ static void movfeatmultedges(void) { trace(" ...\n"); for (combpos=0; combposn_positions; combpos++) { - trace("movfeatmultedges "); trace_combpos(combpos,segment); + trace("movfeatsplitedges "); trace_combpos(combpos,segment); if ((combpos / weight) % subseg->n_positions != edge->movpos) { trace(" excluded\n"); continue; } - newedge= makeedge(masprintf("%s/*%d",edge->pname,combpos), - edge->distance, - starfeature, - combpos); + newedge= edge_create(masprintf("%s/*%d",edge->pname,combpos), + edge->distance, + starfeature, + combpos); FOR_BOTH(end) edgeend_attach(&newedge->ends[end], edge->ends[end].node); } - edge_delete(edge); - /* edge_delete doesn't destroy or modify this edge node, - * so we can safely carry on with this loop, which will - * now carry on with the next edge - either one we've just - * added, or the one which was next before we started messing - * about. - */ + edge_delete(edgeend); } } - trace("movfeatmultedges complete.\n"); + trace("movfeatsplitedges complete.\n"); +} + +static int movfeat_isinnernode(Node *node) { + int side; + EdgeEnd *edgeend; + Segment *all_segment, *segment; + + trace_node(node); + all_segment= 0; + FOR_NODE_EDGEENDS(side,edgeend, node) { + segment= edgeend->edge->subseg->segment; + if (!all_segment) { + all_segment= segment; + } else if (all_segment != segment) { + trace(" not inner: %s and %s\n", + all_segment->segname, segment->segname); + return 0; + } + } + if (!all_segment) { + trace(" not inner: no edges?!\n"); + return 0; + } + trace(" inner %s ",segment->segname); + return 1; } -static void elimtrivial(void) { - /* Eliminate trivial nodes: ones which have only two edges, which - * come in on opposite sides, have the same subsegspec, and with the - * two ends identically aligned. +static EdgeEnd *movfeat_findmate(EdgeEnd *key) { + Node *node; + EdgeEnd *mate; + int mateside; + + node= key->node->node; + mateside= !key->node->side; + + FOR_SIDE_EDGEENDS(mate, node,mateside) { + if (key->edge->subseg == mate->edge->subseg && + key->edge->movpos == mate->edge->movpos && + key->end != mate->end) + return mate; + } + return 0; /* no mate - must be a stub */ +} + +static void movfeatrmstubs(void) { + int pass, anychange, side; + Node *node; + Edge *edge; + EdgeEnd *edgeend, *mate; + + pass= 0; + do { + anychange= 0; + pass++; + trace("movfeatrmstubs pass %d ...\n", pass); + FOR_ALL_NODES(node) { + trace("movfeatrmstubs "); + if (!movfeat_isinnernode(node)) continue; + FOR_NODE_EDGEENDS(side,edgeend, node) { + edge= edgeend->edge; + mate= movfeat_findmate(edgeend); + if (mate) { + trace("("); trace_edgeend(edgeend); trace(")"); + continue; + } + edge_delete(edgeend); + anychange++; + } + trace("\n"); + } + trace("movfeatrmstubs pass %d %s\n", pass, anychange?"changed":"alldone"); + } while (anychange); +} + +static void movfeatsplitnodes(void) { + Node *node, *newnode; + EdgeEnd *edgeend, *mate; + Edge *edge; + int side; + + FOR_ALL_NODES(node) { + trace("movfeatsplitnodes "); + if (!movfeat_isinnernode(node)) continue; + if (!node->sides[0].head->next) { + trace("pair-trivial\n"); + continue; + } + FOR_NODE_EDGEENDS(side,edgeend, node) { + edge= edgeend->edge; + mate= movfeat_findmate(edgeend); + assert(mate); + newnode= node_create(masprintf("%s/*%d",node->pname,edge->movpos)); + edgeend_replumb(mate, &newnode->sides[mate->node->side]); + edgeend_replumb(edgeend, &newnode->sides[edgeend->node->side]); + } + } +} + +static void trivpairnodes(void) { + /* Eliminate near-trivial nodes - in this case, ones which have only + * two edges, which come in on opposite sides, have the same + * subsegspec, and with the two ends identically aligned. */ EdgeEnd *leftedge, *rightedge; - Node *node, *next_node; + Node *node; FOR_ALL_NODES(node) { - next_node=node->next; - trace("elimtrivial node "); trace_node(node); trace(" "); + trace("trivpairnodes node "); trace_node(node); trace(" "); if (!(count_edges(&node->sides[0])==1 && count_edges(&node->sides[1])==1)) { trace("no, a non-unitary side\n"); @@ -413,11 +527,27 @@ static void elimtrivial(void) { masprintf("%s+%s", leftedge->edge->pname, rightedge->edge->pname); rightedge->edge->distance += leftedge->edge->distance; edgeend_replumb(rightedge, edgeend_otherend(leftedge)->node); - edge_delete(leftedge->edge); + edge_delete(leftedge); + trace(" trivpairnodes operation complete\n"); + } +} + +static void trivnullnodes(void) { + /* Eliminate trivial nodes - ones which have no edges. */ + Node *node; + int side; + + trace("trivnullnodes "); + FOR_ALL_NODES(node) { + FOR_BOTH(side) { + if (node->sides[side].head) + goto non_null; + } node_surely_orphaned(node); - trace(" elimtrivial operation complete\n"); + non_null:; } -} + trace(" trivnullnodes done.\n"); +} static void check(const char *why) { Node *node; @@ -439,7 +569,7 @@ static void check(const char *why) { trace(" consistency "); trace_nodeside(&node->sides[side]); trace("\n"); assert(node->sides[side].node == node); assert(node->sides[side].side == side); - for (edgeend=node->sides[side].head; edgeend; edgeend=edgeend->next) { + FOR_SIDE_EDGEENDS(edgeend, node,side) { trace(" consistency "); trace_nodeside(&node->sides[side]); trace(" "); trace_edgeend(edgeend); trace("\n"); @@ -522,8 +652,11 @@ static const OpInfo opinfos[]= { #define OI(x) { #x, x }, OI(printforneato) OI(consistency) - OI(movfeatmultedges) - OI(elimtrivial) + OI(movfeatsplitedges) + OI(movfeatrmstubs) + OI(movfeatsplitnodes) + OI(trivpairnodes) + OI(trivnullnodes) { 0,0 } };