...
1
2
3
4
5 package plotter
6
7 import (
8 "image"
9 "math"
10
11 "gonum.org/v1/plot"
12 "gonum.org/v1/plot/vg"
13 "gonum.org/v1/plot/vg/draw"
14 )
15
16
17 type Image struct {
18 img image.Image
19 cols int
20 rows int
21 xmin, xmax, dx float64
22 ymin, ymax, dy float64
23 }
24
25
26
27
28
29 func NewImage(img image.Image, xmin, ymin, xmax, ymax float64) *Image {
30 if src, ok := img.(*image.Uniform); ok {
31 img = uniform{
32 src,
33 image.Rect(0, 0, int(xmax-xmin+0.5), int(ymax-ymin+0.5)),
34 }
35 }
36 bounds := img.Bounds()
37 cols := bounds.Dx()
38 rows := bounds.Dy()
39 dx := math.Abs(xmax-xmin) / float64(cols)
40 dy := math.Abs(ymax-ymin) / float64(rows)
41 return &Image{
42 img: img,
43 cols: cols,
44 rows: rows,
45 xmin: xmin,
46 xmax: xmax,
47 dx: dx,
48 ymin: ymin,
49 ymax: ymax,
50 dy: dy,
51 }
52 }
53
54
55 func (img *Image) Plot(c draw.Canvas, p *plot.Plot) {
56 trX, trY := p.Transforms(&c)
57 xmin := trX(img.xmin)
58 ymin := trY(img.ymin)
59 xmax := trX(img.xmax)
60 ymax := trY(img.ymax)
61 rect := vg.Rectangle{
62 Min: vg.Point{X: xmin, Y: ymin},
63 Max: vg.Point{X: xmax, Y: ymax},
64 }
65 c.DrawImage(rect, img.transformFor(p))
66 }
67
68
69
70 func (img *Image) DataRange() (xmin, xmax, ymin, ymax float64) {
71 return img.xmin, img.xmax, img.ymin, img.ymax
72 }
73
74
75
76 func (img *Image) GlyphBoxes(plt *plot.Plot) []plot.GlyphBox {
77 return nil
78 }
79
80
81 func (img *Image) transformFor(p *plot.Plot) image.Image {
82 _, xLinear := p.X.Scale.(plot.LinearScale)
83 _, yLinear := p.Y.Scale.(plot.LinearScale)
84 if xLinear && yLinear {
85 return img.img
86 }
87 b := img.img.Bounds()
88 o := image.NewNRGBA64(b)
89 for c := 0; c < img.cols; c++ {
90
91 cTrans := int(p.X.Norm(img.x(c)) * float64(img.cols))
92
93
94 cPrevTrans := int(p.X.Norm(img.x(maxInt(c-1, 0))) * float64(img.cols))
95 for r := 0; r < img.rows; r++ {
96
97 rTrans := int(p.Y.Norm(img.y(r)) * float64(img.rows))
98
99
100 rPrevTrans := int(p.Y.Norm(img.y(maxInt(r-1, 0))) * float64(img.rows))
101 crColor := img.img.At(c, img.rows-r-1)
102
103
104
105 for cPrime := cPrevTrans; cPrime <= cTrans; cPrime++ {
106 for rPrime := rPrevTrans; rPrime <= rTrans; rPrime++ {
107 o.Set(cPrime, img.rows-rPrime-1, crColor)
108 }
109 }
110 }
111 }
112 return o
113 }
114
115 func maxInt(a, b int) int {
116 if a > b {
117 return a
118 }
119 return b
120 }
121
122 func (img *Image) x(c int) float64 {
123 if c >= img.cols || c < 0 {
124 panic("plotter/image: illegal range")
125 }
126 return img.xmin + float64(c)*img.dx
127 }
128
129 func (img *Image) y(r int) float64 {
130 if r >= img.rows || r < 0 {
131 panic("plotter/image: illegal range")
132 }
133 return img.ymin + float64(r)*img.dy
134 }
135
136
137 type uniform struct {
138 *image.Uniform
139 rect image.Rectangle
140 }
141
142 func (img uniform) Bounds() image.Rectangle {
143 return img.rect
144 }
145
View as plain text