Skip to content

Instantly share code, notes, and snippets.

@jphsd
Last active November 7, 2025 19:45
Show Gist options
  • Select an option

  • Save jphsd/b31bd1157e7c59010c0ed15ba67b8e6d to your computer and use it in GitHub Desktop.

Select an option

Save jphsd/b31bd1157e7c59010c0ed15ba67b8e6d to your computer and use it in GitHub Desktop.
//go:build ignore
package main
import (
"flag"
g2d "github.com/jphsd/graphics2d"
"github.com/jphsd/graphics2d/color"
"github.com/jphsd/graphics2d/image"
"math"
"math/rand"
)
// Generalized Brownian motion
func main() {
vf := flag.Float64("v", 1, "variance")
rf := flag.Float64("s", 5, "step size")
tf := flag.Int("t", 1, "max TTL")
flag.Parse()
v, r, mt := *vf, *rf, *tf
w, h := 1000, 1000
bb := [][]float64{{0, 0}, {1000, 1000}}
// Starting from the center
p := []float64{500, 500}
points0 := [][]float64{p}
head := (rand.Float64()*2 - 1) * g2d.Pi
dh := NextDh(v)
ttl := rand.Intn(mt)
orig := head
odh := dh
for PointInBox(p, bb) {
if ttl == 0 {
dh = NextDh(v)
ttl = rand.Intn(mt)
} else {
ttl--
}
head += dh
dx, dy := r*math.Cos(head), r*math.Sin(head)
p = []float64{p[0] + dx, p[1] + dy}
points0 = append(points0, p)
}
np := len(points0)
points := make([][]float64, np, 2*np)
np--
for i, pt := range points0 {
points[np-i] = pt
}
// Now the opposite direction
p = points[np]
head = orig + g2d.Pi
dh = odh
ttl = rand.Intn(mt)
for PointInBox(p, bb) {
if ttl == 0 {
dh = NextDh(v)
ttl = rand.Intn(mt)
} else {
ttl--
}
head += dh
dx, dy := r*math.Cos(head), r*math.Sin(head)
p = []float64{p[0] + dx, p[1] + dy}
points = append(points, p)
}
shape := &g2d.Shape{}
np = len(points)
for i, p := range points {
if i == np-1 {
break
}
shape.AddPaths(g2d.Line(p, points[i+1]))
}
img := image.NewRGBA(w, h, color.White)
g2d.DrawShape(img, shape, g2d.BlackPen)
image.SaveImage(img, "tangle")
}
func NextDh(v float64) float64 {
dh := rand.NormFloat64() * v * g2d.Pi
if dh < -g2d.Pi || dh > g2d.Pi {
// Rather than just clamping since that leads to a fat tail
return NextDh(v)
}
return dh
}
func PointInBox(point []float64, box [][]float64) bool {
if box == nil {
return false
}
return !(point[0] < box[0][0] || point[1] < box[0][1] || point[0] > box[1][0] || point[1] > box[1][1])
}

How To Run

  • Download Go for your platform from here
  • Create a new directory and switch to it
  • Download the .go files from this Gist into it
  • Run $ go mod init main this will create a file called go.mod that's needed for the next step
  • Run $ go mod tidy this will pull down the packages needed to run the program
  • Run $ go run tangle.go
  • The result will be in tangle.png
@jphsd
Copy link
Author

jphsd commented Nov 7, 2025

tangle

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment