diff --git a/gg/gg.go b/gg/gg.go index 242ff66..70ed8ee 100644 --- a/gg/gg.go +++ b/gg/gg.go @@ -353,8 +353,6 @@ func (g *Graph) makeView() { return } - // view only contains value vertices, but we need to keep track of all - // vertices while constructing the view g.byVal = make(map[string]*Vertex, len(g.vM)) g.all = map[string]*Vertex{} @@ -445,7 +443,7 @@ func Equal(g1, g2 *Graph) bool { // passed to the callback and used as the starting point of the traversal. If // the callback returns false the traversal is stopped. func (g *Graph) Walk(startWith *Vertex, callback func(*Vertex) bool) { - // TODO figure out how to make Walk deterministic + // TODO figure out how to make Walk deterministic? g.makeView() if len(g.byVal) == 0 { return diff --git a/gim/main.go b/gim/main.go index f435f61..b7be93b 100644 --- a/gim/main.go +++ b/gim/main.go @@ -17,7 +17,6 @@ import ( // - Absolute positioning of some/all vertices // TODO -// - in current example, order of edges leaving "a" is fucked // - edge values // - be able to draw circular graphs // - audit all steps, make sure everything is deterministic diff --git a/gim/view.go b/gim/view.go index 8ab9ee3..b3a95a1 100644 --- a/gim/view.go +++ b/gim/view.go @@ -19,7 +19,7 @@ import ( // Secondary determines relative position in the secondary direction by // trying to place vertices relative to vertices they share an edge with in // the order that the edges appear on the shared node. -func posSolve(g *gg.Graph) [][]*gg.Vertex { +func posSolve(g *gg.Graph) ([][]*gg.Vertex, map[string]int, map[string]int) { primEng := constraint.NewEngine() secEng := constraint.NewEngine() @@ -83,7 +83,7 @@ func posSolve(g *gg.Graph) [][]*gg.Vertex { out[i][j] = strM[v] } } - return out + return out, prim, sec } // mutates the boxes to be centered around the given point, keeping their @@ -108,7 +108,7 @@ type view struct { } func (view *view) draw(term *terminal.Terminal) { - relPos := posSolve(view.g) + relPos, _, secSol := posSolve(view.g) // create boxes var boxes []*box @@ -116,7 +116,7 @@ func (view *view) draw(term *terminal.Terminal) { boxesMr := map[*gg.Vertex]*box{} const ( primPadding = 5 - secPadding = 3 + secPadding = 1 ) var primPos int for _, vv := range relPos { @@ -146,10 +146,22 @@ func (view *view) draw(term *terminal.Terminal) { primPos += maxPrim + primPadding } + // maps a vertex to all of its to edges, sorted by secSol + findFromIM := map[*gg.Vertex][]gg.Edge{} // returns the index of this edge in from's Out - // TODO this might not be deterministic? Out is never ordered technically findFromI := func(from *gg.Vertex, e gg.Edge) int { - for i, fe := range from.Out { + edges, ok := findFromIM[from] + if !ok { + edges = make([]gg.Edge, len(from.Out)) + copy(edges, from.Out) + sort.Slice(edges, func(i, j int) bool { + // TODO if two edges go to the same vertex, how are they sorted? + return secSol[edges[i].To.ID] < secSol[edges[j].To.ID] + }) + findFromIM[from] = edges + } + + for i, fe := range edges { if fe == e { return i } @@ -163,9 +175,10 @@ func (view *view) draw(term *terminal.Terminal) { v := boxesM[b] for i, e := range v.In { bFrom := boxesMr[e.From] + fromI := findFromI(e.From, e) lines = append(lines, line{ from: bFrom, - fromI: findFromI(e.From, e), + fromI: fromI, to: b, toI: i, })