about summary refs log tree commit diff
path: root/draw/draw.go
blob: de5819193dea52a15c889ef9b8c1534094d24dbb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
package draw

import (
	"git.darknebu.la/GalaxySimulator/Source/structs"
	"github.com/fogleman/gg"
	"math"
)

// initializePlot generates a new plot and returns the plot context
func initializePlot() *gg.Context {
	// Define the image size
	const imageWidth = 8192 * 2
	const imageHeight = 8192 * 2

	// Initialize the new context
	dc := gg.NewContext(imageWidth, imageHeight)

	// Set the background black
	dc.SetRGB(0, 0, 0)
	dc.Clear()

	// Invert the Y axis (positive values are on the top and right)
	dc.InvertY()

	// Set the coordinate midpoint to the middle of the image
	dc.Translate(imageWidth/2, imageHeight/2)

	return dc
}

// saveImages saves the given context to a png at the given path
func saveImage(dc *gg.Context, path string) {
	dc.SavePNG(path)
}

// drawStar draws the given stars to the given context
func drawStar(dc *gg.Context, star structs.Star2D) {
	// User the value below to controll how big the stars are overall
	var starScalingFactor = 50.0

	// Default Star Size
	S := 2.0

	// Calculate the Stars Size according to its Mass (Maximal size = 5)
	if star.M < 5e4 {
		S = float64(math.Ceil(math.Sqrt(star.M)) / starScalingFactor)
	} else {
		S = 5.0
	}

	// draw the star / point
	dc.DrawPoint(star.C.X/50, star.C.Y/50, S)
	dc.Fill()
	dc.Stroke()
}

func drawVelocity(dc *gg.Context, star structs.Star2D) {
	// scaling factor for a better view of the velocity difference
	// Use this value to control how long the vectors are drawn
	var scalingFactor float64 = 50

	// Move the "cursor" to the start position of the vector
	dc.MoveTo(star.C.X/50, star.C.Y/50)

	// calculate the length of the vector
	vecLength := star.V.GetLength()

	// Use a sigmoid function to generate useful values for coloring the vectors according to their
	// strength
	var val = 1.0 / (1.0 + math.Exp(-vecLength*scalingFactor/2*1e8))

	// Set the color to a blue / red
	dc.SetRGB(val, 0, 1-val)

	// calculate the direction vector
	FUnit := (&star.V).Divide(vecLength)

	// set end-position of the vector line
	dc.LineTo(star.C.X/50+(FUnit.X*scalingFactor), star.C.Y/50+(FUnit.Y*scalingFactor))

	// set line width
	dc.SetLineWidth(5)

	// And finally: DRAW (stroke) the vector
	dc.Stroke()
}

// drawStars draws all the stars in the given slice to the given context
func drawStars(dc *gg.Context, slice []structs.Star2D) {
	// draw all the velocity in the given slice
	for _, star := range slice {
		drawVelocity(dc, star)
	}

	dc.SetRGB(1, 1, 1)

	// draw all the stars in the given slice
	for _, star := range slice {
		drawStar(dc, star)
	}
}

// Slice draws the stars and the forces acting on them and saves the result to the given path
func Slice(slice []structs.Star2D, path string) {

	// initialize the plot
	dc := initializePlot()

	// draw all the stars in the given slice
	drawStars(dc, slice)

	// save the plot to the given path
	saveImage(dc, path)
}