~eliasnaur/gio-example

ref: 8a3a65c8c0340253beaba1c2e5687a000fa74789 gio-example/galaxy/galaxy.go -rw-r--r-- 1.8 KiB
8a3a65c8Chris Waldon gio-extras/*,x: rename gio-extras demos and change imports 9 months ago
                                                                                
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
// SPDX-License-Identifier: Unlicense OR MIT

package main

import (
	"log"

	"golang.org/x/exp/rand"

	"gonum.org/v1/gonum/spatial/barneshut"
	"gonum.org/v1/gonum/spatial/r2"
)

type mass struct {
	d r2.Vec  // position
	v r2.Vec  // velocity
	m float64 // mass
}

func (m *mass) Coord2() r2.Vec { return m.d }
func (m *mass) Mass() float64  { return m.m }
func (m *mass) move(f r2.Vec) {
	// F = ma
	f.X /= m.m
	f.Y /= m.m
	m.v = m.v.Add(f)

	// Update position.
	m.d = m.d.Add(m.v)
}

func galaxy(numStars int, rnd *rand.Rand) ([]*mass, barneshut.Plane) {

	// Make 50 stars in random locations and velocities.
	stars := make([]*mass, numStars)
	p := make([]barneshut.Particle2, len(stars))
	for i := range stars {
		s := &mass{
			d: r2.Vec{
				X: 100*rnd.Float64() - 50,
				Y: 100*rnd.Float64() - 50,
			},
			m: rnd.Float64(),
		}
		// Aim at the ground and miss.
		s.d = s.d.Scale(-1).Add(r2.Vec{
			X: 10 * rnd.NormFloat64(),
			Y: 10 * rnd.NormFloat64(),
		})

		stars[i] = s
		p[i] = s
	}
	// Make a plane to calculate approximate forces
	plane := barneshut.Plane{Particles: p}

	return stars, plane
}

func simulate(stars []*mass, plane barneshut.Plane, dist *distribution) {
	vectors := make([]r2.Vec, len(stars))
	// Build the data structure. For small systems
	// this step may be omitted and ForceOn will
	// perform the naive quadratic calculation
	// without building the data structure.
	err := plane.Reset()
	if err != nil {
		log.Fatal(err)
	}

	// Calculate the force vectors using the theta
	// parameter.
	const theta = 0.1
	// and an imaginary gravitational constant.
	const G = 10
	for j, s := range stars {
		vectors[j] = plane.ForceOn(s, theta, barneshut.Gravity2).Scale(G)
	}

	// Update positions.
	for j, s := range stars {
		s.move(vectors[j])
	}

	// Recompute the distribution of stars
	dist.Update(stars)
	dist.EnsureSquare()
}