• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mlange-42 / ark-pixel / 13727326526

07 Mar 2025 06:52PM CUT coverage: 28.089% (-19.3%) from 47.374%
13727326526

push

github

web-flow
Add first plot drawers (#8)

7 of 677 new or added lines in 11 files covered. (1.03%)

457 of 1627 relevant lines covered (28.09%)

55.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/plot/rgb_image.go
1
package plot
2

3
import (
4
        "fmt"
5
        "image/color"
6

7
        pixel "github.com/gopxl/pixel/v2"
8
        "github.com/gopxl/pixel/v2/backends/opengl"
9
        "github.com/mlange-42/ark-pixel/window"
10
        "github.com/mlange-42/ark-tools/observer"
11
        "github.com/mlange-42/ark/ecs"
12
)
13

14
// ImageRGB drawer.
15
//
16
// Draws an image from a Matrix observer per RGB color channel.
17
// The image is scaled to the canvas extent, with preserved aspect ratio.
18
// Does not add plot axes etc.
19
type ImageRGB struct {
20
        Scale    float64               // Spatial scaling: cell size in screen pixels. Optional, default auto.
21
        Observer observer.MatrixLayers // Observer providing data for color channels.
22
        Layers   []int                 // Layer indices. Optional, defaults to [0, 1, 2]. Use -1 to ignore a channel.
23
        Min      []float64             // Minimum value for channel color mapping. Optional, default [0, 0, 0].
24
        Max      []float64             // Maximum value for channel color mapping. Optional, default [1, 1, 1].
25
        slope    []float64
26
        dataLen  int
27
        picture  *pixel.PictureData
28
}
29

30
// Initialize the drawer.
NEW
31
func (i *ImageRGB) Initialize(w *ecs.World, win *opengl.Window) {
×
NEW
32
        i.Observer.Initialize(w)
×
NEW
33

×
NEW
34
        if i.Layers == nil {
×
NEW
35
                i.Layers = []int{0, 1, 2}
×
NEW
36
        } else if len(i.Layers) != 3 {
×
NEW
37
                panic("rgb image plot Layers must be of length 3")
×
38
        }
39

NEW
40
        layers := i.Observer.Layers()
×
NEW
41
        for _, l := range i.Layers {
×
NEW
42
                if l >= 0 && layers <= l {
×
NEW
43
                        panic(fmt.Sprintf("layer index %d out of range", l))
×
44
                }
45
        }
46

NEW
47
        if i.Min == nil {
×
NEW
48
                i.Min = []float64{0, 0, 0}
×
NEW
49
        }
×
NEW
50
        if i.Max == nil {
×
NEW
51
                i.Max = []float64{1, 1, 1}
×
NEW
52
        }
×
NEW
53
        if len(i.Min) != 3 {
×
NEW
54
                panic("RgbImage plot needs exactly 3 Min values")
×
55
        }
NEW
56
        if len(i.Max) != 3 {
×
NEW
57
                panic("RgbImage plot needs exactly 3 Max values")
×
58
        }
59

NEW
60
        i.slope = []float64{
×
NEW
61
                1.0 / (i.Max[0] - i.Min[0]),
×
NEW
62
                1.0 / (i.Max[1] - i.Min[1]),
×
NEW
63
                1.0 / (i.Max[2] - i.Min[2]),
×
NEW
64
        }
×
NEW
65

×
NEW
66
        width, height := i.Observer.Dims()
×
NEW
67
        i.dataLen = width * height
×
NEW
68
        i.picture = pixel.MakePictureData(pixel.R(0, 0, float64(width), float64(height)))
×
69
}
70

71
// Update the drawer.
NEW
72
func (i *ImageRGB) Update(w *ecs.World) {
×
NEW
73
        i.Observer.Update(w)
×
NEW
74
}
×
75

76
// UpdateInputs handles input events of the previous frame update.
NEW
77
func (i *ImageRGB) UpdateInputs(w *ecs.World, win *opengl.Window) {}
×
78

79
// Draw the drawer.
NEW
80
func (i *ImageRGB) Draw(w *ecs.World, win *opengl.Window) {
×
NEW
81
        cannels := i.Observer.Values(w)
×
NEW
82

×
NEW
83
        values := append([]float64{}, i.Min...)
×
NEW
84
        for j := 0; j < i.dataLen; j++ {
×
NEW
85
                for i, k := range i.Layers {
×
NEW
86
                        if k >= 0 {
×
NEW
87
                                values[i] = cannels[k][j]
×
NEW
88
                        }
×
89
                }
NEW
90
                i.picture.Pix[j] = i.valuesToColor(values[0], values[1], values[2])
×
91
        }
92

NEW
93
        scale := i.Scale
×
NEW
94
        if i.Scale <= 0 {
×
NEW
95
                scale = window.Scale(win, i.picture.Rect.W(), i.picture.Rect.H())
×
NEW
96
        }
×
97

NEW
98
        sprite := pixel.NewSprite(i.picture, i.picture.Bounds())
×
NEW
99
        sprite.Draw(win,
×
NEW
100
                pixel.IM.Moved(pixel.V(i.picture.Rect.W()/2.0, i.picture.Rect.H()/2.0)).
×
NEW
101
                        Scaled(pixel.Vec{}, scale),
×
NEW
102
        )
×
103
}
104

NEW
105
func (i *ImageRGB) valuesToColor(r, g, b float64) color.RGBA {
×
NEW
106
        return color.RGBA{
×
NEW
107
                R: norm(r, i.Min[0], i.slope[0]),
×
NEW
108
                G: norm(g, i.Min[1], i.slope[1]),
×
NEW
109
                B: norm(b, i.Min[2], i.slope[2]),
×
NEW
110
                A: 0xff,
×
NEW
111
        }
×
NEW
112
}
×
113

NEW
114
func norm(v, off, slope float64) uint8 {
×
NEW
115
        vv := (v - off) * slope
×
NEW
116
        if vv <= 0 {
×
NEW
117
                return 0
×
NEW
118
        }
×
NEW
119
        if vv >= 1 {
×
NEW
120
                return 255
×
NEW
121
        }
×
NEW
122
        return uint8(vv * 255)
×
123
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc