mirror of
https://github.com/bspeice/speice.io
synced 2025-06-30 21:36:38 -04:00
Proofreading
This commit is contained in:
@ -22,15 +22,14 @@ import banner from '../banner.png'
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
I don't remember exactly when I first learned about fractal flames, but I do remember being entranced by the images they created.
|
||||
I don't remember when exactly I first learned about fractal flames, but I do remember being entranced by the images they created.
|
||||
I also remember their unique appeal to my young engineering mind; this was an art form I could participate in.
|
||||
|
||||
The original [Fractal Flame Algorithm paper](https://flam3.com/flame_draves.pdf) describing their structure was too much
|
||||
The [Fractal Flame Algorithm paper](https://flam3.com/flame_draves.pdf) describing their structure was too much
|
||||
for me to handle at the time (I was ~12 years old), so I was content to play around and enjoy the pictures.
|
||||
But the desire to understand it stuck around. Now, with a graduate degree under my belt, I want to revisit it
|
||||
and try to make some progress.
|
||||
But the desire to understand it stuck around. Now, with a graduate degree under my belt, I wanted to revisit it.
|
||||
|
||||
This guide is my attempt to explain how fractal flames work in a way that younger me — and others interested in the art —
|
||||
This guide is my attempt to explain how fractal flames work so that younger me — and others interested in the art —
|
||||
can understand without too much prior knowledge.
|
||||
|
||||
---
|
||||
@ -42,7 +41,7 @@ This post covers section 2 of the Fractal Flame Algorithm paper
|
||||
:::
|
||||
|
||||
As mentioned, fractal flames are a type of "[iterated function system](https://en.wikipedia.org/wiki/Iterated_function_system),"
|
||||
or IFS. The formula for an IFS is short, but takes some time to unpack:
|
||||
or IFS. The formula for an IFS is short, but takes some time to work through:
|
||||
|
||||
$$
|
||||
S = \bigcup_{i=0}^{n-1} F_i(S)
|
||||
@ -52,7 +51,7 @@ $$
|
||||
|
||||
First, $S$. $S$ is the set of points in two dimensions (in math terms, $S \in \mathbb{R}^2$)
|
||||
that represent a "solution" of some kind to our equation.
|
||||
Our goal is to find all points in $S$, plot them, and display that image.
|
||||
Our goal is to find all the points in $S$, plot them, and display that image.
|
||||
|
||||
For example, if we say $S = \{(0,0), (1, 1), (2, 2)\}$, there are three points to plot:
|
||||
|
||||
@ -67,20 +66,17 @@ export const simpleData = [
|
||||
<VictoryScatter data={simpleData} size={5} style={{data: {fill: "blue"}}}/>
|
||||
</VictoryChart>
|
||||
|
||||
However, this is a pretty boring image. With fractal flames, rather than listing individual points,
|
||||
we use functions to describe which points are part of the solution. This means there are an infinite
|
||||
number of points, but if we find _enough_ points to plot, we'll end up with a nice picture.
|
||||
And if the functions change, the solution also changes, and we get a new picture.
|
||||
With fractal flames, rather than listing individual points, we use functions to describe the solution.
|
||||
This means there are an infinite number of points, but if we find _enough_ points to plot, we get a nice picture.
|
||||
And if the functions change, the solution also changes, and we get something new.
|
||||
|
||||
### Transform functions
|
||||
|
||||
Second, the $F_i(S)$ functions, also known as "transforms."
|
||||
At their most basic, each $F_i$ takes in a 2-dimensional point and gives back a new point
|
||||
Each transform takes in a 2-dimensional point and gives a new point back
|
||||
(in math terms, $F_i \in \mathbb{R}^2 \rightarrow \mathbb{R}^2$).
|
||||
While you could theoretically use any function, we'll start with a specific kind of function
|
||||
called an "[affine transformation](https://en.wikipedia.org/wiki/Affine_transformation)."
|
||||
|
||||
The general form of an affine transformation is:
|
||||
While you could theoretically use any function, we'll focus on a specific kind of function
|
||||
called an "[affine transformation](https://en.wikipedia.org/wiki/Affine_transformation)." Every transform uses the same formula:
|
||||
|
||||
$$
|
||||
F_i(a_i x + b_i y + c_i, d_i x + e_i y + f_i)
|
||||
@ -91,8 +87,8 @@ import CodeBlock from '@theme/CodeBlock'
|
||||
|
||||
<CodeBlock language="typescript">{transformSource}</CodeBlock>
|
||||
|
||||
The parameters ($a_i$, $b_i$, etc.) are values we get to choose.
|
||||
For example, we can represent a "shift" function like this:
|
||||
The parameters ($a_i$, $b_i$, etc.) are values we choose.
|
||||
For example, we can define a "shift" function like this:
|
||||
|
||||
$$
|
||||
\begin{align*}
|
||||
@ -106,7 +102,7 @@ F_{shift}(x, y) &= (1 \cdot x + 0.5, 1 \cdot y + 1.5)
|
||||
\end{align*}
|
||||
$$
|
||||
|
||||
Applying this function to our original points will give us a new set of points:
|
||||
Applying this transform to the original points gives us a new set of points:
|
||||
|
||||
import {applyCoefs} from "../src/transform"
|
||||
|
||||
@ -139,7 +135,7 @@ $$
|
||||
S = \bigcup_{i=0}^{n-1} F_i(S)
|
||||
$$
|
||||
|
||||
Or, to put it in English, we might say:
|
||||
Or, in English, we might say:
|
||||
|
||||
> Our solution, $S$, is the union of all sets produced by applying each function, $F_i$,
|
||||
> to points in the solution.
|
||||
@ -153,17 +149,13 @@ defining the mathematics of iterated function systems:
|
||||
> Furthermore, $S$ is compact and is the closure of the set of fixed points $s_{i_1...i_p}$
|
||||
> of finite compositions $F_{i_1...i_p}$ of members of $F$.
|
||||
|
||||
:::note
|
||||
I've tweaked the conventions of that paper slightly to match the Fractal Flame paper
|
||||
:::
|
||||
|
||||
Before your eyes glaze over, let's unpack this:
|
||||
|
||||
- **Furthermore, $S$ is [compact](https://en.wikipedia.org/wiki/Compact_space)...**: All points in our solution will be in a finite range
|
||||
- **...and is the [closure](https://en.wikipedia.org/wiki/Closure_(mathematics)) of the set of [fixed points](https://en.wikipedia.org/wiki/Fixed_point_(mathematics))**:
|
||||
Applying our functions to points in the solution will give us other points that are in the solution
|
||||
- **...of finite compositions $F_{i_1...i_p}$ of members of $F$**: By composing our functions (that is,
|
||||
using the output of one function as input to the next function), we will arrive at the points in the solution
|
||||
using the output of one function as input to the next), we will arrive at the points in the solution
|
||||
|
||||
Thus, by applying the functions to fixed points of our system, we will find the other points we care about.
|
||||
|
||||
@ -177,11 +169,11 @@ Thus, by applying the functions to fixed points of our system, we will find the
|
||||
algorithm demonstrates, we only need functions to be contractive _on average_. At worst, the system will
|
||||
degenerate and produce a bad image.
|
||||
|
||||
Second, we're focused on $\mathbb{R}^2$ because we're generating images, but the Hutchinson paper
|
||||
Second, we're focused on $\mathbb{R}^2$ because we're generating images, but the math
|
||||
allows for arbitrary dimensions; you could also have 3-dimensional fractal flames.
|
||||
|
||||
Finally, there's a close relationship between fractal flames and [attractors](https://en.wikipedia.org/wiki/Attractor).
|
||||
Specifically, the fixed points of $S$ act as attractors for the chaos game (explained in more detail below).
|
||||
Specifically, the fixed points of $S$ act as attractors for the chaos game (explained below).
|
||||
</details>
|
||||
|
||||
This is still a bit vague, so let's work through an example.
|
||||
@ -200,7 +192,7 @@ $$
|
||||
|
||||
### The chaos game
|
||||
|
||||
Next, how do we find the "fixed points" mentioned earlier? The paper lays out an algorithm called the "[chaos game](https://en.wikipedia.org/wiki/Chaos_game)"
|
||||
Now, how do we find the "fixed points" mentioned earlier? The paper lays out an algorithm called the "[chaos game](https://en.wikipedia.org/wiki/Chaos_game)"
|
||||
that gives us points in the solution:
|
||||
|
||||
$$
|
||||
@ -220,8 +212,8 @@ The chaos game algorithm is effectively the "finite compositions of $F_{i_1..i_p
|
||||
|
||||
Let's turn this into code, one piece at a time.
|
||||
|
||||
First, we need to generate some random numbers. The "bi-unit square" is the range $[-1, 1]$,
|
||||
so we generate a random point using an existing API:
|
||||
To start, we need to generate some random numbers. The "bi-unit square" is the range $[-1, 1]$,
|
||||
and we can do this using an existing API:
|
||||
|
||||
import biunitSource from '!!raw-loader!../src/randomBiUnit'
|
||||
|
||||
@ -235,14 +227,14 @@ import randintSource from '!!raw-loader!../src/randomInteger'
|
||||
|
||||
### Plotting
|
||||
|
||||
Finally, implementing the `plot` function. This blog series is designed to be interactive,
|
||||
Finally, implementing the `plot` function. This blog series is interactive,
|
||||
so everything displays directly in the browser. As an alternative,
|
||||
software like `flam3` and Apophysis can "plot" by saving an image to disk.
|
||||
|
||||
To show the results, we'll use the [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API).
|
||||
This allows us to manipulate individual pixels in an image and display it on screen.
|
||||
To see the results, we'll use the [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API).
|
||||
This allows us to manipulate individual pixels in an image and show it on screen.
|
||||
|
||||
First, we need to convert from Fractal Flame coordinates to pixel coordinates.
|
||||
First, we need to convert from fractal flame coordinates to pixel coordinates.
|
||||
To simplify things, we'll assume that we're plotting a square image
|
||||
with range $[0, 1]$ for both $x$ and $y$:
|
||||
|
||||
@ -251,7 +243,7 @@ import cameraSource from "!!raw-loader!./cameraGasket"
|
||||
<CodeBlock language="typescript">{cameraSource}</CodeBlock>
|
||||
|
||||
Next, we'll store the pixel data in an [`ImageData` object](https://developer.mozilla.org/en-US/docs/Web/API/ImageData).
|
||||
Each pixel in the image on screen has a corresponding index in the `data` array.
|
||||
Each pixel on screen has a corresponding index in the `data` array.
|
||||
To plot a point, we set that pixel to be black:
|
||||
|
||||
import plotSource from '!!raw-loader!./plot'
|
||||
@ -277,25 +269,22 @@ import chaosGameSource from '!!raw-loader!./chaosGame'
|
||||
|
||||
### Weights
|
||||
|
||||
There's one last step before we finish the introduction. So far, each function $F_i$ has
|
||||
the same chance of being chosen. We can change that by introducing a "weight" ($w_i$)
|
||||
to each transform in the chaos game:
|
||||
There's one last step before we finish the introduction. So far, each transform has
|
||||
the same chance of being picked in the chaos game.
|
||||
We can change that by giving them a "weight" ($w_i$) instead:
|
||||
|
||||
import randomChoiceSource from '!!raw-loader!../src/randomChoice'
|
||||
|
||||
<CodeBlock language={'typescript'}>{randomChoiceSource}</CodeBlock>
|
||||
|
||||
If we let the chaos game run forever, these weights wouldn't matter.
|
||||
But because the iteration count is limited, changing the weights
|
||||
means we don't plot some parts of the image:
|
||||
|
||||
import chaosGameWeightedSource from "!!raw-loader!./chaosGameWeighted";
|
||||
|
||||
<CodeBlock language={'typescript'}>{chaosGameWeightedSource}</CodeBlock>
|
||||
|
||||
For Sierpinski's Gasket, we start with equal weighting,
|
||||
but changing the transform weights affects how often
|
||||
the chaos game "visits" parts of the image. If the chaos
|
||||
were to run forever, we'd get the same image;
|
||||
but because the iteration count is limited,
|
||||
some parts may be missing below.
|
||||
|
||||
:::tip
|
||||
Double-click the image if you want to save a copy!
|
||||
:::
|
||||
@ -308,7 +297,7 @@ import {SquareCanvas} from "../src/Canvas";
|
||||
## Summary
|
||||
|
||||
Studying the foundations of fractal flames is challenging,
|
||||
but we now have an understanding of both the mathematics
|
||||
and implementations of iterated function systems.
|
||||
but we now have an understanding of the mathematics
|
||||
and the implementation of iterated function systems.
|
||||
|
||||
In the next post, we'll study the first innovation of fractal flames: variations.
|
||||
In the next post, we'll look at the first innovation of fractal flame algorithm: variations.
|
Reference in New Issue
Block a user