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) }