github.com/gopherd/gonum@v0.0.4/graph/layout/optimizer.go (about) 1 // Copyright ©2019 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package layout 6 7 import ( 8 "github.com/gopherd/gonum/graph" 9 "github.com/gopherd/gonum/spatial/r2" 10 ) 11 12 // LayoutR2 implements graph layout updates and representations. 13 type LayoutR2 interface { 14 // IsInitialized returns whether the Layout is initialized. 15 IsInitialized() bool 16 17 // SetCoord2 sets the coordinates of the node with the given 18 // id to coords. 19 SetCoord2(id int64, coords r2.Vec) 20 21 // Coord2 returns the coordinated of the node with the given 22 // id in the graph layout. 23 Coord2(id int64) r2.Vec 24 } 25 26 // NewOptimizerR2 returns a new layout optimizer. If g implements LayoutR2 the layout 27 // will be updated into g, otherwise the OptimizerR2 will hold the graph layout. A nil 28 // value for update is a valid no-op layout update function. 29 func NewOptimizerR2(g graph.Graph, update func(graph.Graph, LayoutR2) bool) OptimizerR2 { 30 l, ok := g.(LayoutR2) 31 if !ok { 32 l = make(coordinatesR2) 33 } 34 return OptimizerR2{ 35 g: g, 36 layout: l, 37 Updater: update, 38 } 39 } 40 41 // coordinatesR2 is the default layout store for R2. 42 type coordinatesR2 map[int64]r2.Vec 43 44 func (c coordinatesR2) IsInitialized() bool { return len(c) != 0 } 45 func (c coordinatesR2) SetCoord2(id int64, pos r2.Vec) { c[id] = pos } 46 func (c coordinatesR2) Coord2(id int64) r2.Vec { return c[id] } 47 48 // OptimizerR2 is a helper type that holds a graph and layout 49 // optimization state. 50 type OptimizerR2 struct { 51 g graph.Graph 52 layout LayoutR2 53 54 // Updater is the function called for each call to Update. 55 // It updates the OptimizerR2's spatial distribution of the 56 // nodes in the backing graph. 57 Updater func(graph.Graph, LayoutR2) bool 58 } 59 60 // Coord2 returns the location of the node with the given 61 // ID. The returned value is only valid if the node exists 62 // in the graph. 63 func (g OptimizerR2) Coord2(id int64) r2.Vec { 64 return g.layout.Coord2(id) 65 } 66 67 // Update updates the locations of the nodes in the graph 68 // according to the provided update function. It returns whether 69 // the update function is able to further refine the graph's 70 // node locations. 71 func (g OptimizerR2) Update() bool { 72 if g.Updater == nil { 73 return false 74 } 75 return g.Updater(g.g, g.layout) 76 } 77 78 // LayoutNodeR2 implements the GraphR2 interface. 79 func (g OptimizerR2) LayoutNodeR2(id int64) NodeR2 { 80 n := g.g.Node(id) 81 if n == nil { 82 return NodeR2{} 83 } 84 return NodeR2{Node: n, Coord2: g.Coord2(id)} 85 } 86 87 // Node returns the node with the given ID if it exists 88 // in the graph, and nil otherwise. 89 func (g OptimizerR2) Node(id int64) graph.Node { return g.g.Node(id) } 90 91 // Nodes returns all the nodes in the graph. 92 func (g OptimizerR2) Nodes() graph.Nodes { return g.g.Nodes() } 93 94 // From returns all nodes that can be reached directly 95 // from the node with the given ID. 96 func (g OptimizerR2) From(id int64) graph.Nodes { return g.g.From(id) } 97 98 // HasEdgeBetween returns whether an edge exists between 99 // nodes with IDs xid and yid without considering direction. 100 func (g OptimizerR2) HasEdgeBetween(xid, yid int64) bool { return g.g.HasEdgeBetween(xid, yid) } 101 102 // Edge returns the edge from u to v, with IDs uid and vid, 103 // if such an edge exists and nil otherwise. The node v 104 // must be directly reachable from u as defined by the 105 // From method. 106 func (g OptimizerR2) Edge(uid, vid int64) graph.Edge { return g.g.Edge(uid, vid) }