fractal

package
v0.8.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package fractal provides pure–Go, standard-library-only tools for computing and exploring classic fractals.

The package is organized around several independent topics:

  • Escape-time fractals: the Mandelbrot set and Julia sets, including per-point escape iteration counts, smooth (normalized) iteration counts for continuous coloring, closed-form interior tests (main cardioid and period-2 bulb), and evaluation over a rectangular grid via a Viewport.
  • Fractal dimension: box-counting dimension of a finite point set, a generic log-log least-squares slope helper, and the exact self-similar (Hausdorff) dimension of strictly self-similar sets.
  • L-systems: deterministic context-free string rewriting (LSystem) plus a turtle-graphics interpreter that turns a command string into line [Segment]s or a vertex path, with presets for the Koch curve, Sierpinski triangle, dragon curve, and a branching plant.
  • Iterated function systems: affine contraction maps (AffineMap), the random "chaos game" (IFS.ChaosGame), and presets for the Barnsley fern and Sierpinski triangle/carpet.
  • Deterministic geometric fractals: the Koch curve and snowflake, the Sierpinski triangle by recursive subdivision, and the Cantor set.

All routines use only the Go standard library and are deterministic: any randomness (the chaos game) is driven by an explicit caller-supplied seed.

Complex numbers are represented with the builtin complex128 type; planar points use Point2D.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BoxCount

func BoxCount(points []Point2D, boxSize float64) int

BoxCount returns the number of distinct axis-aligned grid boxes of side boxSize that contain at least one of the given points. It panics if boxSize is not positive. This is the count N(epsilon) used in box-counting dimension estimation.

func BoxCountingDimension

func BoxCountingDimension(points []Point2D, boxSizes []float64) float64

BoxCountingDimension estimates the box-counting (Minkowski–Bouligand) dimension of a finite point set by counting occupied boxes at each of the given box sizes and returning the slope of log N(epsilon) versus log(1/epsilon). At least two box sizes are required; the sizes must be positive. Smaller boxes give a better estimate for a true fractal but require densely sampled points.

func BoxCountingDimensionFromCounts

func BoxCountingDimensionFromCounts(boxSizes, counts []float64) float64

BoxCountingDimensionFromCounts estimates a fractal dimension directly from a table of (box size, occupied-box count) samples: it returns the slope of log(count) versus log(1/size). This is useful when counts were obtained externally. The slices must have equal length of at least two, and all entries must be positive. For an exact power law count = k*size^(-D) the returned value is exactly D.

func FitLine

func FitLine(xs, ys []float64) (slope, intercept float64)

FitLine returns the slope and intercept of the ordinary least-squares line y = slope*x + intercept fitted to the paired samples xs, ys. It panics if the slices differ in length or contain fewer than two points. When every x is identical the slope is 0 and the intercept is the mean of ys.

func FitSlope

func FitSlope(xs, ys []float64) float64

FitSlope returns the slope of the ordinary least-squares line y = m*x + b fitted to the paired samples xs, ys. It panics if the slices differ in length or contain fewer than two points, and returns 0 when every x is identical.

func HausdorffDimensionSelfSimilar

func HausdorffDimensionSelfSimilar(n int, scale float64) float64

HausdorffDimensionSelfSimilar returns the exact similarity (Hausdorff) dimension of a strictly self-similar set composed of n non-overlapping copies of itself, each scaled by the ratio scale (0 < scale < 1). The dimension is log(n)/log(1/scale). For example n=3, scale=1/2 gives the Sierpinski triangle dimension log2(3) ≈ 1.585; n=4, scale=1/3 gives the Koch curve dimension log(4)/log(3) ≈ 1.262. It panics if n < 1 or scale is not in (0,1).

func InJuliaSet

func InJuliaSet(z, c complex128, maxIter int) bool

InJuliaSet reports whether the seed z lies in the filled Julia set of z -> z^2 + c, i.e. whether its orbit fails to escape radius 2 within maxIter iterations.

func InMainCardioid

func InMainCardioid(c complex128) bool

InMainCardioid reports, in closed form, whether c lies inside the main cardioid of the Mandelbrot set — the large heart-shaped region containing all c for which z -> z^2 + c has an attracting fixed point. Writing p = |c - 1/4| = sqrt((Re c - 1/4)^2 + (Im c)^2), the membership criterion is Re(c) <= p - 2*p^2 + 1/4, which holds exactly on the closed cardioid.

func InMandelbrotSet

func InMandelbrotSet(c complex128, maxIter int) bool

InMandelbrotSet reports whether c lies in the Mandelbrot set, i.e. whether the orbit of z -> z^2 + c starting at 0 fails to escape radius 2 within maxIter iterations. Because the test is truncated at maxIter, points very near the boundary may be misclassified as members.

func InPeriod2Bulb

func InPeriod2Bulb(c complex128) bool

InPeriod2Bulb reports, in closed form, whether c lies inside the period-2 bulb of the Mandelbrot set: the disk of radius 1/4 centered at -1. Membership is exactly |c + 1| <= 1/4.

func JuliaSmooth

func JuliaSmooth(z, c complex128, maxIter int, bailout float64) float64

JuliaSmooth returns the smooth (fractional) escape iteration count for the Julia map z -> z^2 + c seeded at z. See EscapeResult.Smooth.

func MandelbrotSmooth

func MandelbrotSmooth(c complex128, maxIter int, bailout float64) float64

MandelbrotSmooth returns the smooth (fractional) escape iteration count for the Mandelbrot map at c. See EscapeResult.Smooth. A large bailout (for example 256) gives the smoothest result.

func Orbit

func Orbit(z0, c complex128, n int) []complex128

Orbit returns the first n+1 points of the orbit of z -> z^2 + c starting at z0, that is [z0, f(z0), f(f(z0)), ...] of length n+1. For n < 0 it returns nil.

Types

type AffineMap

type AffineMap struct {
	A, B, C, D, E, F float64
}

AffineMap is a 2-D affine transformation of the form

x' = A*x + B*y + E
y' = C*x + D*y + F

Such contraction maps are the building blocks of iterated function systems.

func NewAffineMap

func NewAffineMap(a, b, c, d, e, f float64) AffineMap

NewAffineMap constructs an AffineMap from its six coefficients in the order a, b, c, d, e, f matching the field layout x' = a*x+b*y+e, y' = c*x+d*y+f.

func (AffineMap) Apply

func (m AffineMap) Apply(p Point2D) Point2D

Apply returns the image of p under the affine map.

type EscapeResult

type EscapeResult struct {
	Escaped    bool
	Iterations int
	FinalZ     complex128
}

EscapeResult records the outcome of iterating a quadratic map z -> z^2 + c until the orbit escapes a bailout radius or a maximum iteration count is reached. Escaped reports whether the bailout was exceeded; Iterations is the number of completed iterations at that moment (equal to the maximum when the orbit did not escape); FinalZ is the last computed orbit value.

func JuliaEscape

func JuliaEscape(z, c complex128, maxIter int, bailout float64) EscapeResult

JuliaEscape computes the escape-time result for the filled Julia set of the map z -> z^2 + c starting from the seed point z. The orbit escapes once |z| exceeds bailout (at least 2). Iteration stops after maxIter steps.

func MandelbrotEscape

func MandelbrotEscape(c complex128, maxIter int, bailout float64) EscapeResult

MandelbrotEscape computes the escape-time result for the Mandelbrot map z -> z^2 + c starting from z = 0. The point c is considered to have escaped once |z| exceeds bailout (which should be at least 2, the Mandelbrot escape radius). Iteration stops after maxIter steps.

func (EscapeResult) Smooth

func (r EscapeResult) Smooth(bailout float64) float64

Smooth returns the fractional (normalized) iteration count for an escaped result, giving continuous values suitable for smooth coloring. It uses the standard renormalization mu = n + 1 - log2(log|z| / log(bailout)). For a result that did not escape it returns the integer iteration count unchanged. The estimate is most accurate when bailout is large (for example 256).

type Grid

type Grid struct {
	Width, Height int
	Data          []float64
}

Grid is a dense Width×Height array of scalar values stored in row-major order (index = y*Width + x). It is the natural output of rasterizing an escape-time fractal over a rectangular region.

func JuliaGrid

func JuliaGrid(c complex128, v Viewport, width, height, maxIter int, bailout float64) *Grid

JuliaGrid rasterizes the filled Julia set of z -> z^2 + c over the given viewport into a width×height Grid. Each cell holds the smooth escape iteration count of the seed sampled at that pixel. Row 0 corresponds to the top of the viewport.

func MandelbrotGrid

func MandelbrotGrid(v Viewport, width, height, maxIter int, bailout float64) *Grid

MandelbrotGrid rasterizes the Mandelbrot set over the given viewport into a width×height Grid. Each cell holds the smooth escape iteration count (see EscapeResult.Smooth) of the complex value sampled at that pixel, so interior (non-escaping) points hold maxIter. Row 0 corresponds to the top of the viewport. See Viewport.PixelToComplex for the pixel-to-complex mapping.

func NewGrid

func NewGrid(width, height int) *Grid

NewGrid allocates a zero-filled Grid with the given dimensions. It panics if width or height is negative.

func (*Grid) At

func (g *Grid) At(x, y int) float64

At returns the value at column x, row y. It panics if the coordinates are out of range.

func (*Grid) Clone

func (g *Grid) Clone() *Grid

Clone returns a deep copy of the grid.

func (*Grid) CountFinite

func (g *Grid) CountFinite() int

CountFinite returns the number of grid cells whose value is finite (neither NaN nor infinite).

func (*Grid) Max

func (g *Grid) Max() float64

Max returns the largest value in the grid, or 0 for an empty grid.

func (*Grid) Mean

func (g *Grid) Mean() float64

Mean returns the arithmetic mean of all grid values, or 0 for an empty grid.

func (*Grid) Min

func (g *Grid) Min() float64

Min returns the smallest value in the grid, or 0 for an empty grid.

func (*Grid) MinMax

func (g *Grid) MinMax() (min, max float64)

MinMax returns the minimum and maximum values in the grid. For an empty grid it returns (0, 0).

func (*Grid) Normalize

func (g *Grid) Normalize() *Grid

Normalize returns a new Grid whose values are linearly rescaled so that the original minimum maps to 0 and the original maximum maps to 1. If all values are equal the result is all zeros. The receiver is not modified.

func (*Grid) Row

func (g *Grid) Row(y int) []float64

Row returns the y-th row of the grid as a slice that aliases the underlying storage. Mutating it mutates the grid.

func (*Grid) Set

func (g *Grid) Set(x, y int, v float64)

Set stores v at column x, row y. It panics if the coordinates are out of range.

type IFS

type IFS struct {
	Maps    []AffineMap
	Weights []float64
}

IFS is an iterated function system: a list of affine contraction Maps with an equal-length list of selection Weights. When run as a chaos game the map at index i is chosen with probability Weights[i] / sum(Weights). If Weights is nil or empty the maps are chosen uniformly.

func BarnsleyFern

func BarnsleyFern() IFS

BarnsleyFern returns the four-map iterated function system that generates Michael Barnsley's fern. The maps and their selection probabilities are the classical values; the attractor fits within roughly x in [-2.2, 2.7] and y in [0, 10].

func SierpinskiCarpetIFS

func SierpinskiCarpetIFS() IFS

SierpinskiCarpetIFS returns the eight-map iterated function system whose attractor is the Sierpinski carpet: the unit square is divided into a 3x3 grid and every cell except the center maps back to the whole via a 1/3-scale contraction. The maps are chosen with equal probability.

func SierpinskiTriangleIFS

func SierpinskiTriangleIFS() IFS

SierpinskiTriangleIFS returns the three-map iterated function system whose attractor is the Sierpinski triangle with vertices (0,0), (1,0) and (0.5, 0.5). Each map scales the plane by 1/2 toward one vertex; the maps are chosen with equal probability.

func (IFS) ChaosGame

func (s IFS) ChaosGame(n int, seed int64) []Point2D

ChaosGame runs the chaos game starting from the origin, discarding 20 transient points, and returns n attractor points. It is a convenience wrapper around IFS.ChaosGameFrom. The output is deterministic for a given seed.

func (IFS) ChaosGameFrom

func (s IFS) ChaosGameFrom(start Point2D, n, transient int, seed int64) []Point2D

ChaosGameFrom runs the random-iteration ("chaos game") algorithm starting from the point start: it repeatedly picks a map according to the system's weights and applies it, discarding the first transient points before recording n points. Randomness is driven solely by seed, so the output is fully deterministic for a given seed. It returns n points and panics if the system has no maps or n is negative.

type Interval

type Interval struct {
	Start, End float64
}

Interval is a closed real interval [Start, End].

func CantorSet

func CantorSet(start, end float64, iterations int) []Interval

CantorSet returns the intervals remaining after iterations steps of the middle-thirds Cantor construction applied to [start, end]. Iteration 0 returns the single interval [start, end]; each step replaces every interval by its first and last thirds, so the result contains 2^iterations intervals with total length (end-start)*(2/3)^iterations. Intervals are returned in increasing order. It panics if iterations is negative.

func (Interval) Length

func (iv Interval) Length() float64

Length returns End - Start.

type LSystem

type LSystem struct {
	Axiom string
	Rules map[rune]string
}

LSystem is a deterministic context-free Lindenmayer system: an Axiom string and a set of production Rules mapping a single symbol (rune) to a replacement string. Symbols with no rule are left unchanged (they act as constants).

func DragonLSystem

func DragonLSystem() LSystem

DragonLSystem returns the Heighway dragon curve L-system: axiom "F" with rules X -> X+YF+ and Y -> -FX-Y, rendered with a turn angle of 90 degrees. The symbols X and Y control the recursion and draw nothing themselves.

func KochLSystem

func KochLSystem() LSystem

KochLSystem returns the classic Koch curve L-system: axiom "F" with the rule F -> F+F--F+F. Rendered with a turn angle of 60 degrees it produces the Koch curve.

func NewLSystem

func NewLSystem(axiom string, rules map[rune]string) LSystem

NewLSystem constructs an LSystem from an axiom and a rule map. The rule map is copied so later mutation of the argument does not affect the system.

func PlantLSystem

func PlantLSystem() LSystem

PlantLSystem returns a branching plant L-system: axiom "X" with rules X -> F+[[X]-X]-F[-FX]+X and F -> FF, rendered with a turn angle of about 25 degrees. It uses the bracket commands to create branches.

func SierpinskiLSystem

func SierpinskiLSystem() LSystem

SierpinskiLSystem returns an L-system whose turtle rendering (turn angle 60 degrees) draws the Sierpinski triangle. Axiom "F-G-G" with rules F -> F-G+F+G-F and G -> GG.

func (LSystem) Expand

func (l LSystem) Expand(iterations int) string

Expand applies the production rules iterations times starting from the axiom and returns the resulting string. Zero iterations returns the axiom itself. It panics if iterations is negative.

func (LSystem) Step

func (l LSystem) Step(s string) string

Step applies every production rule once to s in parallel, replacing each symbol by its rule's right-hand side (or leaving it unchanged if it has no rule) and returning the rewritten string.

type Point2D

type Point2D struct {
	X, Y float64
}

Point2D is a point in the Euclidean plane with coordinates X and Y.

func BoundingBox

func BoundingBox(pts []Point2D) (min, max Point2D)

BoundingBox returns the axis-aligned bounding box of pts as its minimum and maximum corners. It returns two zero points when pts is empty.

func KochCurve

func KochCurve(p0, p1 Point2D, iterations int) []Point2D

KochCurve returns the polyline vertices of the Koch curve constructed between the endpoints p0 and p1 after the given number of iterations. Iteration 0 returns the two endpoints [p0, p1]; each further iteration replaces every segment by four segments (a bump raised on its middle third), so the result has 4^iterations + 1 points. Bumps are raised to the left of the p0->p1 direction. It panics if iterations is negative.

func KochSnowflake

func KochSnowflake(center Point2D, radius float64, iterations int) []Point2D

KochSnowflake returns the closed polyline of the Koch snowflake inscribed in the circle of the given radius centered at center, after the given number of iterations. The base is an equilateral triangle whose corners lie on the circle; each edge is replaced by a Koch curve with bumps pointing outward. The returned slice is closed (its last point equals its first). It panics if iterations is negative.

func TurtlePath

func TurtlePath(commands string, cfg TurtleConfig) []Point2D

TurtlePath interprets a command string and returns the ordered vertices visited by the turtle: the start position followed by the endpoint of every forward move (both drawing and non-drawing). It is intended for non-branching L-systems; when brackets are present the returned polyline includes the jumps created by popping the stack. See Turtle for the command set.

func (Point2D) Add

func (p Point2D) Add(q Point2D) Point2D

Add returns the vector sum p+q.

func (Point2D) Dist

func (p Point2D) Dist(q Point2D) float64

Dist returns the Euclidean distance between p and q.

func (Point2D) Lerp

func (p Point2D) Lerp(q Point2D, t float64) Point2D

Lerp returns the linear interpolation between p (t=0) and q (t=1).

func (Point2D) Midpoint

func (p Point2D) Midpoint(q Point2D) Point2D

Midpoint returns the point halfway between p and q.

func (Point2D) Norm

func (p Point2D) Norm() float64

Norm returns the Euclidean length of p treated as a vector from the origin.

func (Point2D) Rotate

func (p Point2D) Rotate(angle float64) Point2D

Rotate returns p rotated counterclockwise about the origin by angle radians.

func (Point2D) Scale

func (p Point2D) Scale(s float64) Point2D

Scale returns p with both coordinates multiplied by s.

func (Point2D) Sub

func (p Point2D) Sub(q Point2D) Point2D

Sub returns the vector difference p-q.

type Segment

type Segment struct {
	X0, Y0, X1, Y1 float64
}

Segment is a directed line segment from (X0,Y0) to (X1,Y1), the drawing primitive produced by the turtle interpreter.

func Turtle

func Turtle(commands string, cfg TurtleConfig) []Segment

Turtle interprets a command string as turtle graphics and returns the drawn line segments. The recognized commands are:

F, G : move forward by Step, drawing a segment
f, g : move forward by Step without drawing
+    : turn left  (counterclockwise) by AngleDeg
-    : turn right (clockwise)        by AngleDeg
|    : turn around (180 degrees)
[    : push the current state onto a stack
]    : pop and restore the most recently pushed state

All other symbols are ignored, so L-system variables such as 'X' and 'Y' act as no-ops. Bracketed sections produce disconnected segment groups, allowing branching structures.

type Triangle

type Triangle struct {
	A, B, C Point2D
}

Triangle is a triangle with vertices A, B and C.

func SierpinskiTriangle

func SierpinskiTriangle(a, b, c Point2D, depth int) []Triangle

SierpinskiTriangle returns the list of filled sub-triangles produced by recursively removing the central triangle from the triangle (a, b, c) to the given depth. Depth 0 returns the single input triangle; each level replaces every triangle by its three corner sub-triangles, so the result contains 3^depth triangles. It panics if depth is negative.

type TurtleConfig

type TurtleConfig struct {
	Step          float64
	AngleDeg      float64
	StartAngleDeg float64
	Start         Point2D
}

TurtleConfig parameterizes the turtle-graphics interpreter. Step is the forward move length; AngleDeg is the turn angle in degrees applied by the '+' and '-' commands; StartAngleDeg is the initial heading in degrees measured counterclockwise from the positive x-axis; Start is the initial pen position.

type TurtleState

type TurtleState struct {
	Pos     Point2D
	HeadDeg float64
}

TurtleState is the pose of the turtle: its position and its heading in radians measured counterclockwise from the positive x-axis.

type Viewport

type Viewport struct {
	XMin, XMax, YMin, YMax float64
}

Viewport is an axis-aligned rectangle in the complex plane, used to map integer pixel coordinates onto complex values. XMin/XMax bound the real axis and YMin/YMax bound the imaginary axis.

func NewViewport

func NewViewport(centerRe, centerIm, radius float64) Viewport

NewViewport returns the square viewport centered at (centerRe, centerIm) with the given half-width (radius) along each axis.

func (Viewport) Aspect

func (v Viewport) Aspect() float64

Aspect returns the width-to-height ratio of the viewport. It returns 0 when the height is zero.

func (Viewport) Center

func (v Viewport) Center() complex128

Center returns the complex number at the center of the viewport.

func (Viewport) PixelToComplex

func (v Viewport) PixelToComplex(px, py, width, height int) complex128

PixelToComplex maps the pixel at column px, row py of a width×height raster to the complex value it samples. Column 0 maps to XMin and column width-1 maps to XMax; row 0 maps to YMax (top) and row height-1 maps to YMin (bottom), so increasing the row index moves downward as is conventional for images. When width or height is 1 the corresponding axis collapses to its minimum edge.

func (Viewport) SpanX

func (v Viewport) SpanX() float64

SpanX returns the width of the viewport along the real axis.

func (Viewport) SpanY

func (v Viewport) SpanY() float64

SpanY returns the height of the viewport along the imaginary axis.

func (Viewport) Zoom

func (v Viewport) Zoom(factor float64) Viewport

Zoom returns a new viewport with the same center whose span along each axis is multiplied by factor. A factor below 1 zooms in; above 1 zooms out.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL