mirror of
https://github.com/gonum/gonum.git
synced 2025-10-09 09:00:38 +08:00
graph/layout: reduce code duplication in layout tests
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
// Copyright ©2021 The Gonum Authors. All rights reserved.
|
// Copyright ©2019 The Gonum Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file
|
// license that can be found in the LICENSE file
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package layout
|
package layout_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -15,6 +15,8 @@ import (
|
|||||||
"gonum.org/v1/gonum/spatial/r2"
|
"gonum.org/v1/gonum/spatial/r2"
|
||||||
"gonum.org/v1/plot"
|
"gonum.org/v1/plot"
|
||||||
"gonum.org/v1/plot/vg"
|
"gonum.org/v1/plot/vg"
|
||||||
|
|
||||||
|
. "gonum.org/v1/gonum/graph/layout"
|
||||||
)
|
)
|
||||||
|
|
||||||
var eadesR2Tests = []struct {
|
var eadesR2Tests = []struct {
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
// +build 386
|
// +build 386
|
||||||
|
|
||||||
package layout
|
package layout_test
|
||||||
|
|
||||||
// Change the testdata path for calculations done on 386.
|
// Change the testdata path for calculations done on 386.
|
||||||
func init() {
|
func init() {
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
// +build arm64
|
// +build arm64
|
||||||
|
|
||||||
package layout
|
package layout_test
|
||||||
|
|
||||||
// Change the testdata path for calculations done on arm64.
|
// Change the testdata path for calculations done on arm64.
|
||||||
func init() {
|
func init() {
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
// +build noasm gccgo safe
|
// +build noasm gccgo safe
|
||||||
|
|
||||||
package layout
|
package layout_test
|
||||||
|
|
||||||
// Change the testdata path for calculations done without assembly kernels.
|
// Change the testdata path for calculations done without assembly kernels.
|
||||||
func init() {
|
func init() {
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package layout
|
package layout_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -13,6 +13,8 @@ import (
|
|||||||
"gonum.org/v1/gonum/spatial/r2"
|
"gonum.org/v1/gonum/spatial/r2"
|
||||||
"gonum.org/v1/plot"
|
"gonum.org/v1/plot"
|
||||||
"gonum.org/v1/plot/vg"
|
"gonum.org/v1/plot/vg"
|
||||||
|
|
||||||
|
. "gonum.org/v1/gonum/graph/layout"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package layout
|
package layout_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
@@ -1,145 +0,0 @@
|
|||||||
// 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 (
|
|
||||||
"fmt"
|
|
||||||
"image/color"
|
|
||||||
"math"
|
|
||||||
|
|
||||||
"gonum.org/v1/plot"
|
|
||||||
"gonum.org/v1/plot/plotter"
|
|
||||||
"gonum.org/v1/plot/vg"
|
|
||||||
"gonum.org/v1/plot/vg/draw"
|
|
||||||
)
|
|
||||||
|
|
||||||
const radius = vg.Length(15)
|
|
||||||
|
|
||||||
// render implements the plot.Plotter interface for graphs.
|
|
||||||
type render struct {
|
|
||||||
GraphR2
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p render) Plot(c draw.Canvas, plt *plot.Plot) {
|
|
||||||
nodes := p.GraphR2.Nodes()
|
|
||||||
if nodes.Len() == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
xys plotter.XYs
|
|
||||||
ids []string
|
|
||||||
)
|
|
||||||
if nodes.Len() >= 0 {
|
|
||||||
xys = make(plotter.XYs, 0, nodes.Len())
|
|
||||||
ids = make([]string, 0, nodes.Len())
|
|
||||||
}
|
|
||||||
for nodes.Next() {
|
|
||||||
u := nodes.Node()
|
|
||||||
uid := u.ID()
|
|
||||||
ur2 := p.GraphR2.LayoutNodeR2(uid)
|
|
||||||
xys = append(xys, plotter.XY(ur2.Coord2))
|
|
||||||
ids = append(ids, fmt.Sprint(uid))
|
|
||||||
to := p.GraphR2.From(uid)
|
|
||||||
for to.Next() {
|
|
||||||
v := to.Node()
|
|
||||||
vid := v.ID()
|
|
||||||
vr2 := p.GraphR2.LayoutNodeR2(vid)
|
|
||||||
|
|
||||||
l, err := plotter.NewLine(plotter.XYs{plotter.XY(ur2.Coord2), plotter.XY(vr2.Coord2)})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
l.Plot(c, plt)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := plotter.NewScatter(xys)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
n.GlyphStyle.Shape = nodeGlyph{}
|
|
||||||
n.GlyphStyle.Radius = radius
|
|
||||||
n.Plot(c, plt)
|
|
||||||
|
|
||||||
l, err := plotter.NewLabels(plotter.XYLabels{XYs: xys, Labels: ids})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
fnt, err := vg.MakeFont(plot.DefaultFont, vg.Points(18))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
for i := range l.TextStyle {
|
|
||||||
l.TextStyle[i] = draw.TextStyle{Font: fnt, XAlign: draw.XCenter, YAlign: -0.25}
|
|
||||||
}
|
|
||||||
|
|
||||||
l.Plot(c, plt)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DataRange returns the minimum and maximum X and Y values
|
|
||||||
func (p render) DataRange() (xmin, xmax, ymin, ymax float64) {
|
|
||||||
nodes := p.GraphR2.Nodes()
|
|
||||||
if nodes.Len() == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var xys plotter.XYs
|
|
||||||
if nodes.Len() >= 0 {
|
|
||||||
xys = make(plotter.XYs, 0, nodes.Len())
|
|
||||||
}
|
|
||||||
for nodes.Next() {
|
|
||||||
u := nodes.Node()
|
|
||||||
uid := u.ID()
|
|
||||||
ur2 := p.GraphR2.LayoutNodeR2(uid)
|
|
||||||
xys = append(xys, plotter.XY(ur2.Coord2))
|
|
||||||
}
|
|
||||||
return plotter.XYRange(xys)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GlyphBoxes returns a slice of plot.GlyphBoxes, implementing the
|
|
||||||
// plot.GlyphBoxer interface.
|
|
||||||
func (p render) GlyphBoxes(plt *plot.Plot) []plot.GlyphBox {
|
|
||||||
nodes := p.GraphR2.Nodes()
|
|
||||||
if nodes.Len() == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var b []plot.GlyphBox
|
|
||||||
if nodes.Len() >= 0 {
|
|
||||||
b = make([]plot.GlyphBox, 0, nodes.Len())
|
|
||||||
}
|
|
||||||
for i := 0; nodes.Next(); i++ {
|
|
||||||
u := nodes.Node()
|
|
||||||
uid := u.ID()
|
|
||||||
ur2 := p.GraphR2.LayoutNodeR2(uid)
|
|
||||||
|
|
||||||
b = append(b, plot.GlyphBox{})
|
|
||||||
b[i].X = plt.X.Norm(ur2.Coord2.X)
|
|
||||||
b[i].Y = plt.Y.Norm(ur2.Coord2.Y)
|
|
||||||
r := radius
|
|
||||||
b[i].Rectangle = vg.Rectangle{
|
|
||||||
Min: vg.Point{X: -r, Y: -r},
|
|
||||||
Max: vg.Point{X: +r, Y: +r},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
// nodeGlyph is a glyph that draws a filled circle.
|
|
||||||
type nodeGlyph struct{}
|
|
||||||
|
|
||||||
// DrawGlyph implements the GlyphDrawer interface.
|
|
||||||
func (nodeGlyph) DrawGlyph(c *draw.Canvas, sty draw.GlyphStyle, pt vg.Point) {
|
|
||||||
var p vg.Path
|
|
||||||
c.Push()
|
|
||||||
c.SetColor(color.White)
|
|
||||||
p.Move(vg.Point{X: pt.X + sty.Radius, Y: pt.Y})
|
|
||||||
p.Arc(pt, sty.Radius, 0, 2*math.Pi)
|
|
||||||
p.Close()
|
|
||||||
c.Fill(p)
|
|
||||||
c.Pop()
|
|
||||||
c.Stroke(p)
|
|
||||||
}
|
|
Reference in New Issue
Block a user