mirror of
https://github.com/gonum/gonum.git
synced 2025-10-26 08:40:26 +08:00
graph/layout: new package for calculating graph layouts
This commit is contained in:
106
graph/layout/optimizer.go
Normal file
106
graph/layout/optimizer.go
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright ©2019 The Gonum Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package layout
|
||||
|
||||
import (
|
||||
"gonum.org/v1/gonum/graph"
|
||||
"gonum.org/v1/gonum/spatial/r2"
|
||||
)
|
||||
|
||||
// LayoutR2 implements graph layout updates and representations.
|
||||
type LayoutR2 interface {
|
||||
// IsInitialized returns whether the Layout is initialized.
|
||||
IsInitialized() bool
|
||||
|
||||
// SetCoord2 sets the coordinates of the node with the given
|
||||
// id to coords.
|
||||
SetCoord2(id int64, coords r2.Vec)
|
||||
|
||||
// Coord2 returns the coordinated of the node with the given
|
||||
// id in the graph layout.
|
||||
Coord2(id int64) r2.Vec
|
||||
}
|
||||
|
||||
// NewOptimizerR2 returns a new layout optimizer. If g implements LayoutR2 the layout
|
||||
// will be updated into g, otherwise the OptimizerR2 will hold the graph layout. A nil
|
||||
// value for update is a valid no-op layout update function.
|
||||
func NewOptimizerR2(g graph.Graph, update func(graph.Graph, LayoutR2) bool) OptimizerR2 {
|
||||
l, ok := g.(LayoutR2)
|
||||
if !ok {
|
||||
l = make(coordinatesR2)
|
||||
}
|
||||
return OptimizerR2{
|
||||
g: g,
|
||||
layout: l,
|
||||
Updater: update,
|
||||
}
|
||||
}
|
||||
|
||||
// coordinatesR2 is the default layout store for R2.
|
||||
type coordinatesR2 map[int64]r2.Vec
|
||||
|
||||
func (c coordinatesR2) IsInitialized() bool { return len(c) != 0 }
|
||||
func (c coordinatesR2) SetCoord2(id int64, pos r2.Vec) { c[id] = pos }
|
||||
func (c coordinatesR2) Coord2(id int64) r2.Vec { return c[id] }
|
||||
|
||||
// OptimizerR2 is a helper type that holds a graph and layout
|
||||
// optimization state.
|
||||
type OptimizerR2 struct {
|
||||
g graph.Graph
|
||||
layout LayoutR2
|
||||
|
||||
// Updater is the function called for each call to Update.
|
||||
// It updates the OptimizerR2's spatial distribution of the
|
||||
// nodes in the backing graph.
|
||||
Updater func(graph.Graph, LayoutR2) bool
|
||||
}
|
||||
|
||||
// Coord2 returns the location of the node with the given
|
||||
// ID. The returned value is only valid if the node exists
|
||||
// in the graph.
|
||||
func (g OptimizerR2) Coord2(id int64) r2.Vec {
|
||||
return g.layout.Coord2(id)
|
||||
}
|
||||
|
||||
// Update updates the locations of the nodes in the graph
|
||||
// according to the provided update function. It returns whether
|
||||
// the update function is able to further refine the graph's
|
||||
// node locations.
|
||||
func (g OptimizerR2) Update() bool {
|
||||
if g.Updater == nil {
|
||||
return false
|
||||
}
|
||||
return g.Updater(g.g, g.layout)
|
||||
}
|
||||
|
||||
// LayoutNodeR2 implements the GraphR2 interface.
|
||||
func (g OptimizerR2) LayoutNodeR2(id int64) NodeR2 {
|
||||
n := g.g.Node(id)
|
||||
if n == nil {
|
||||
return NodeR2{}
|
||||
}
|
||||
return NodeR2{Node: n, Coord2: g.Coord2(id)}
|
||||
}
|
||||
|
||||
// Node returns the node with the given ID if it exists
|
||||
// in the graph, and nil otherwise.
|
||||
func (g OptimizerR2) Node(id int64) graph.Node { return g.g.Node(id) }
|
||||
|
||||
// Nodes returns all the nodes in the graph.
|
||||
func (g OptimizerR2) Nodes() graph.Nodes { return g.g.Nodes() }
|
||||
|
||||
// From returns all nodes that can be reached directly
|
||||
// from the node with the given ID.
|
||||
func (g OptimizerR2) From(id int64) graph.Nodes { return g.g.From(id) }
|
||||
|
||||
// HasEdgeBetween returns whether an edge exists between
|
||||
// nodes with IDs xid and yid without considering direction.
|
||||
func (g OptimizerR2) HasEdgeBetween(xid, yid int64) bool { return g.g.HasEdgeBetween(xid, yid) }
|
||||
|
||||
// Edge returns the edge from u to v, with IDs uid and vid,
|
||||
// if such an edge exists and nil otherwise. The node v
|
||||
// must be directly reachable from u as defined by the
|
||||
// From method.
|
||||
func (g OptimizerR2) Edge(uid, vid int64) graph.Edge { return g.g.Edge(uid, vid) }
|
||||
Reference in New Issue
Block a user