mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 16:48:10 -05:00
Reorganize a bit, write some more
This commit is contained in:
parent
431ba2d0f4
commit
aba3c9f988
@ -51,7 +51,7 @@ First, $S$. We're generating images, so everything is in two dimensions: $S \in
|
|||||||
all points that are "in the system." To generate our final image, we just plot every point in the system
|
all points that are "in the system." To generate our final image, we just plot every point in the system
|
||||||
like a coordinate chart.
|
like a coordinate chart.
|
||||||
|
|
||||||
TODO: What is a stationary point? How does it relate to the chaos game?
|
TODO: What is a stationary point? How does it relate to the chaos game? Why does the chaos game work?
|
||||||
|
|
||||||
For example, if we say $S = \{(0,0), (1, 1), (2, 2)\}$, there are three points to plot:
|
For example, if we say $S = \{(0,0), (1, 1), (2, 2)\}$, there are three points to plot:
|
||||||
|
|
||||||
@ -188,3 +188,5 @@ import Gasket from '!!raw-loader!./Gasket'
|
|||||||
Note: The image our chaos game generates is different than the fractal flame paper, but I think the version displayed
|
Note: The image our chaos game generates is different than the fractal flame paper, but I think the version displayed
|
||||||
here is correct. As confirmation, the next post will re-create the same image using a different method.
|
here is correct. As confirmation, the next post will re-create the same image using a different method.
|
||||||
</small>
|
</small>
|
||||||
|
|
||||||
|
TODO: Explanation of function weights $w_i$
|
@ -0,0 +1,5 @@
|
|||||||
|
import {useColorMode, useThemeConfig} from "@docusaurus/theme-common";
|
||||||
|
|
||||||
|
export default function BaselineRender({children}) {
|
||||||
|
const {colorMode, setColorMode} = useColorMode();
|
||||||
|
}
|
22
blog/2024-11-15-playing-with-fire/2-transforms/baseline.ts
Normal file
22
blog/2024-11-15-playing-with-fire/2-transforms/baseline.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
// hidden-start
|
||||||
|
import { Coefs } from './coefs'
|
||||||
|
import { Variation } from './variations'
|
||||||
|
// hidden-end
|
||||||
|
export function applyTransform(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
coefs: Coefs,
|
||||||
|
variations: [number, Variation][])
|
||||||
|
{
|
||||||
|
const transformX = coefs.a * x + coefs.b * y + coefs.c;
|
||||||
|
const transformY = coefs.d * x + coefs.e * y + coefs.f;
|
||||||
|
|
||||||
|
var finalX = 0;
|
||||||
|
var finalY = 0;
|
||||||
|
for (const [blend, variation] of variations) {
|
||||||
|
const [variationX, variationY] = variation(transformX, transformY);
|
||||||
|
finalX += blend * variationX;
|
||||||
|
finalY += blend * variationY;
|
||||||
|
}
|
||||||
|
return [finalX, finalY];
|
||||||
|
}
|
@ -25,6 +25,10 @@ $$
|
|||||||
F_i(x,y) = (a_i \cdot x + b_i \cdot y + c_i, \hspace{0.2cm} d_i \cdot x + e_i \cdot y + f_i)
|
F_i(x,y) = (a_i \cdot x + b_i \cdot y + c_i, \hspace{0.2cm} d_i \cdot x + e_i \cdot y + f_i)
|
||||||
$$
|
$$
|
||||||
|
|
||||||
|
import coefsSrc from '!!raw-loader!../src/coefs'
|
||||||
|
|
||||||
|
<CodeBlock language={'typescript'}>{coefsSrc}</CodeBlock>
|
||||||
|
|
||||||
We also introduced the Sierpinski Gasket functions ($F_0$, $F_1$, and $F_2$), demonstrating how they are related to
|
We also introduced the Sierpinski Gasket functions ($F_0$, $F_1$, and $F_2$), demonstrating how they are related to
|
||||||
the general format. For example:
|
the general format. For example:
|
||||||
|
|
||||||
@ -37,7 +41,7 @@ F_0(x,y) &= \left({x \over 2}, {y \over 2}\right) \\
|
|||||||
\end{align*}
|
\end{align*}
|
||||||
$$
|
$$
|
||||||
|
|
||||||
However, these transforms are pretty boring. We can build more exciting images by using some additional functions
|
However, these transforms are pretty boring. We can build more exciting images by using additional functions
|
||||||
within the transform. These "sub-functions" are called "variations":
|
within the transform. These "sub-functions" are called "variations":
|
||||||
|
|
||||||
$$
|
$$
|
||||||
@ -52,18 +56,18 @@ Our reference image will focus on just four variations:
|
|||||||
|
|
||||||
### Linear (variation 0)
|
### Linear (variation 0)
|
||||||
|
|
||||||
This variation returns the $x$ and $y$ coordinates as-is. As mentioned, the Sierpinski Gasket is
|
This variation returns the $x$ and $y$ coordinates as-is:
|
||||||
a fractal flame using only the linear variation:
|
|
||||||
|
|
||||||
$$
|
$$
|
||||||
V_0(x,y) = (x,y)
|
V_0(x,y) = (x,y)
|
||||||
$$
|
$$
|
||||||
|
|
||||||
```typescript
|
import linearSrc from '!!raw-loader!../src/linear'
|
||||||
function linear(x: number, y: number) {
|
|
||||||
return [x, y];
|
<CodeBlock language={'typescript'}>{linearSrc}</CodeBlock>
|
||||||
}
|
|
||||||
```
|
Before we move on, it's worth mentioning the relationship between this variation and the Sierpinski Gasket.
|
||||||
|
Specifically, we can think of the Gasket as a fractal flame that uses only the linear variation.
|
||||||
|
|
||||||
### Julia (variation 13)
|
### Julia (variation 13)
|
||||||
|
|
||||||
@ -86,18 +90,9 @@ V_{13}(x, y) &= \sqrt{r} \cdot (\text{cos} ( \theta / 2 + \Omega ), \text{sin} (
|
|||||||
\end{align*}
|
\end{align*}
|
||||||
$$
|
$$
|
||||||
|
|
||||||
```typescript
|
import juliaSrc from '!!raw-loader!../src/julia'
|
||||||
function julia(x: number, y: number) {
|
|
||||||
const r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
|
|
||||||
const theta = Math.atan2(x, y);
|
|
||||||
const omega = Math.random() > 0.5 ? 0 : Math.PI;
|
|
||||||
|
|
||||||
return [
|
<CodeBlock language={'typescript'}>{juliaSrc}</CodeBlock>
|
||||||
r * Math.cos(theta / 2 + omega),
|
|
||||||
r * Math.sin(theta / 2 + omega)
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Popcorn (variation 17)
|
### Popcorn (variation 17)
|
||||||
|
|
||||||
@ -108,14 +103,9 @@ $$
|
|||||||
V_{17}(x,y) = (x + c \cdot \text{sin}(\text{tan }3y), y + f \cdot \text{sin}(\text{tan }3x))
|
V_{17}(x,y) = (x + c \cdot \text{sin}(\text{tan }3y), y + f \cdot \text{sin}(\text{tan }3x))
|
||||||
$$
|
$$
|
||||||
|
|
||||||
```typescript
|
import popcornSrc from '!!raw-loader!../src/popcorn'
|
||||||
function popcorn(coefs: {c: number, f: number}) {
|
|
||||||
return (x: number, y: number) => [
|
<CodeBlock language={'typescript'}>{popcornSrc}</CodeBlock>
|
||||||
x + coefs.c * Math.sin(Math.tan(3 * y)),
|
|
||||||
y + coefs.f * Math.sin(Math.tan(3 * x))
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### PDJ (variation 24)
|
### PDJ (variation 24)
|
||||||
|
|
||||||
@ -126,11 +116,27 @@ p_1 = \text{pdj.a} \hspace{0.2cm} p_2 = \text{pdj.b} \hspace{0.2cm} p_3 = \text{
|
|||||||
V_{24} = (\text{sin}(p_1 \cdot y) - \text{cos}(p_2 \cdot x), \text{sin}(p_3 \cdot x) - \text{cos}(p_4 \cdot y))
|
V_{24} = (\text{sin}(p_1 \cdot y) - \text{cos}(p_2 \cdot x), \text{sin}(p_3 \cdot x) - \text{cos}(p_4 \cdot y))
|
||||||
$$
|
$$
|
||||||
|
|
||||||
```typescript
|
import pdjSrc from '!!raw-loader!../src/pdj'
|
||||||
function pdj(a: number, b: number, c: number, d: number) {
|
|
||||||
return (x: number, y: number) => [
|
<CodeBlock language={'typescript'}>{pdjSrc}</CodeBlock>
|
||||||
Math.sin(a * y) - Math.cos(b * x),
|
|
||||||
Math.sin(c * x) - Math.cos(d * y)
|
### Blending
|
||||||
]
|
|
||||||
}
|
Now, one variation is fun, but we can also combine variations in a single transform by "blending."
|
||||||
```
|
First, each variation is assigned a value that describes how much it affects the transform function ($v_j$).
|
||||||
|
Afterward, sum up the $x$ and $y$ values respectively:
|
||||||
|
|
||||||
|
$$
|
||||||
|
F_i(x,y) = \sum_{j} v_{ij} V_j(a_i \cdot x + b_i \cdot y + c_i, \hspace{0.2cm} d_i \cdot x + e_i \cdot y + f_i)
|
||||||
|
$$
|
||||||
|
|
||||||
|
The formula looks intimidating, but it's not hard to implement:
|
||||||
|
|
||||||
|
import baselineSrc from '!!raw-loader!./baseline'
|
||||||
|
|
||||||
|
<CodeBlock language={'typescript'}>{baselineSrc}</CodeBlock>
|
||||||
|
|
||||||
|
TODO: Mention that the Sierpinski Gasket is just a blend with linear weight 1, all others 0. Maybe replace comment above about Sierpinski Gasket and linear transform?
|
||||||
|
|
||||||
|
And with that in place, we have enough to render a first full fractal flame:
|
||||||
|
|
||||||
|
13
blog/2024-11-15-playing-with-fire/src/julia.ts
Normal file
13
blog/2024-11-15-playing-with-fire/src/julia.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
// hidden-start
|
||||||
|
import { Variation } from './variations'
|
||||||
|
// hidden-end
|
||||||
|
export const julia: Variation = (x, y) => {
|
||||||
|
const r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
|
||||||
|
const theta = Math.atan2(x, y);
|
||||||
|
const omega = Math.random() > 0.5 ? 0 : Math.PI;
|
||||||
|
|
||||||
|
return [
|
||||||
|
r * Math.cos(theta / 2 + omega),
|
||||||
|
r * Math.sin(theta / 2 + omega)
|
||||||
|
]
|
||||||
|
}
|
4
blog/2024-11-15-playing-with-fire/src/linear.ts
Normal file
4
blog/2024-11-15-playing-with-fire/src/linear.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// hidden-start
|
||||||
|
import {Variation} from "./variations"
|
||||||
|
//hidden-end
|
||||||
|
export const linear: Variation = (x, y) => [x, y];
|
@ -3,8 +3,12 @@
|
|||||||
* translated into something that's easier to work with.
|
* translated into something that's easier to work with.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Coefs, Transform} from "./types";
|
import { Coefs } from './coefs';
|
||||||
import { julia, linear, pdj, popcorn } from "./variation";
|
import { Transform } from './transform';
|
||||||
|
import { linear } from './linear'
|
||||||
|
import { julia } from './julia'
|
||||||
|
import { popcorn } from './popcorn'
|
||||||
|
import { pdj } from './pdj'
|
||||||
|
|
||||||
export const identityCoefs: Coefs = {
|
export const identityCoefs: Coefs = {
|
||||||
a: 1, b: 0, c: 0,
|
a: 1, b: 0, c: 0,
|
||||||
@ -12,53 +16,51 @@ export const identityCoefs: Coefs = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const xform1Weight = 0.56453495;
|
export const xform1Weight = 0.56453495;
|
||||||
export const xform1: Transform = {
|
export const xform1Coefs = {
|
||||||
coefs: {
|
a: -1.381068, b: -1.381068, c: 0,
|
||||||
a: -1.381068, b: -1.381068, c: 0,
|
d: 1.381068, e: -1.381068, f: 0,
|
||||||
d: 1.381068, e: -1.381068, f: 0,
|
|
||||||
},
|
|
||||||
coefsPost: identityCoefs,
|
|
||||||
variations: [[1, julia]],
|
|
||||||
color: 0
|
|
||||||
}
|
}
|
||||||
|
export const xform1CoefsPost = identityCoefs;
|
||||||
|
export const xform1Variations = [
|
||||||
|
[1, julia]
|
||||||
|
]
|
||||||
|
export const xform1Color = 0;
|
||||||
|
|
||||||
const xform2Weight = 0.013135;
|
export const xform2Weight = 0.013135;
|
||||||
export const xform2: Transform = {
|
export const xform2Coefs = {
|
||||||
coefs: {
|
a: 0.031393, b: 0.031367, c: 0,
|
||||||
a: 0.031393, b: 0.031367, c: 0,
|
d: -0.031367, e: 0.031393, f: 0,
|
||||||
d: -0.031367, e: 0.031393, f: 0,
|
|
||||||
},
|
|
||||||
coefsPost: {
|
|
||||||
a: 1, b: 0, c: 0.241352,
|
|
||||||
d: 0, e: 1, f: 0.271521,
|
|
||||||
},
|
|
||||||
variations: [
|
|
||||||
[1, linear],
|
|
||||||
[1, popcorn]
|
|
||||||
],
|
|
||||||
color: 0.844
|
|
||||||
}
|
}
|
||||||
|
export const xform2CoefsPost = {
|
||||||
|
a: 1, b: 0, c: 0.241352,
|
||||||
|
d: 0, e: 1, f: 0.271521,
|
||||||
|
}
|
||||||
|
export const xform2Variations = [
|
||||||
|
[1, linear],
|
||||||
|
[1, popcorn(xform2Coefs)]
|
||||||
|
]
|
||||||
|
export const xform2Color = 0.844;
|
||||||
|
|
||||||
export const xform3Weight = 0.42233;
|
export const xform3Weight = 0.42233;
|
||||||
export const xform3: Transform = {
|
export const xform3Coefs = {
|
||||||
coefs: {
|
a: 1.51523, b: -3.048677, c: 0.724135,
|
||||||
a: 1.51523, b: -3.048677, c: 0.724135,
|
d: 0.740356, e: -1.455964, f: -0.362059,
|
||||||
d: 0.740356, e: -1.455964, f: -0.362059,
|
|
||||||
},
|
|
||||||
coefsPost: identityCoefs,
|
|
||||||
variations: [[1, pdj(1.09358, 2.13048, 2.54127, 2.37267)]],
|
|
||||||
color: 0.349
|
|
||||||
}
|
}
|
||||||
|
export const xform3CoefsPost = identityCoefs;
|
||||||
|
export const xform3Variations = [
|
||||||
|
[1, pdj(1.09358, 2.13048, 2.54127, 2.37267)]
|
||||||
|
];
|
||||||
|
export const xform3Color = 0.349;
|
||||||
|
|
||||||
export const xformFinal: Transform = {
|
export const xformFinalCoefs = {
|
||||||
coefs: {
|
a: 2, b: 0, c: 0,
|
||||||
a: 2, b: 0, c: 0,
|
d: 0, e: 2, f: 0
|
||||||
d: 0, e: 2, f: 0
|
|
||||||
},
|
|
||||||
coefsPost: identityCoefs,
|
|
||||||
variations: [[1, julia]],
|
|
||||||
color: 0
|
|
||||||
}
|
}
|
||||||
|
export const xformFinalCoefsPost = identityCoefs;
|
||||||
|
export const xformFinalVariations = [
|
||||||
|
[1, julia]
|
||||||
|
]
|
||||||
|
export const xformFinalColor = 0;
|
||||||
|
|
||||||
export const palette =
|
export const palette =
|
||||||
"7E3037762C45722B496E2A4E6A2950672853652754632656" +
|
"7E3037762C45722B496E2A4E6A2950672853652754632656" +
|
9
blog/2024-11-15-playing-with-fire/src/pdj.ts
Normal file
9
blog/2024-11-15-playing-with-fire/src/pdj.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// hidden-start
|
||||||
|
import { Variation } from './variations'
|
||||||
|
//hidden-end
|
||||||
|
export function pdj(a: number, b: number, c: number, d: number): Variation {
|
||||||
|
return (x, y) => [
|
||||||
|
Math.sin(a * y) - Math.cos(b * x),
|
||||||
|
Math.sin(c * x) - Math.cos(d * y)
|
||||||
|
]
|
||||||
|
}
|
10
blog/2024-11-15-playing-with-fire/src/popcorn.ts
Normal file
10
blog/2024-11-15-playing-with-fire/src/popcorn.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// hidden-start
|
||||||
|
import {Coefs} from './coefs'
|
||||||
|
import {Variation} from './variations'
|
||||||
|
// hidden-end
|
||||||
|
export function popcorn({c, f}: Coefs): Variation {
|
||||||
|
return (x, y) => [
|
||||||
|
x + c * Math.sin(Math.tan(3 * y)),
|
||||||
|
y + f * Math.sin(Math.tan(3 * x))
|
||||||
|
];
|
||||||
|
}
|
9
blog/2024-11-15-playing-with-fire/src/transform.ts
Normal file
9
blog/2024-11-15-playing-with-fire/src/transform.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Coefs } from './coefs'
|
||||||
|
import { Variation } from './variations'
|
||||||
|
|
||||||
|
export interface Transform {
|
||||||
|
coefs: Coefs,
|
||||||
|
variations: [number, Variation][],
|
||||||
|
coefsPost: Coefs,
|
||||||
|
color: number
|
||||||
|
}
|
1
blog/2024-11-15-playing-with-fire/src/variations.ts
Normal file
1
blog/2024-11-15-playing-with-fire/src/variations.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export type Variation = (x: number, y: number) => [number, number];
|
@ -1,24 +0,0 @@
|
|||||||
/**
|
|
||||||
* Affine transformation coefficients
|
|
||||||
*/
|
|
||||||
export type Coefs = {
|
|
||||||
a: number;
|
|
||||||
b: number;
|
|
||||||
c: number;
|
|
||||||
d: number;
|
|
||||||
e: number;
|
|
||||||
f: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type Variation = (
|
|
||||||
x: number,
|
|
||||||
y: number,
|
|
||||||
coefs: Coefs
|
|
||||||
) => [number, number];
|
|
||||||
|
|
||||||
export type Transform = {
|
|
||||||
coefs: Coefs,
|
|
||||||
coefsPost: Coefs,
|
|
||||||
variations: [number, Variation][],
|
|
||||||
color: number
|
|
||||||
}
|
|
@ -1,40 +0,0 @@
|
|||||||
import { Variation } from "./types";
|
|
||||||
|
|
||||||
export const linear: Variation = (x, y) => [x, y];
|
|
||||||
|
|
||||||
function r(x: number, y: number) {
|
|
||||||
return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
function theta(x: number, y: number) {
|
|
||||||
return Math.atan2(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
function omega(): number {
|
|
||||||
return Math.random() > 0.5 ? Math.PI : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const julia: Variation = (x, y) => {
|
|
||||||
const sqrtR = Math.sqrt(r(x, y));
|
|
||||||
const thetaVal = theta(x, y) / 2 + omega();
|
|
||||||
return [sqrtR * Math.cos(thetaVal), sqrtR * Math.sin(thetaVal)];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const popcorn: Variation = (x, y, transformCoefs) => {
|
|
||||||
return [
|
|
||||||
x + transformCoefs.c * Math.sin(Math.tan(3 * y)),
|
|
||||||
y + transformCoefs.f * Math.sin(Math.tan(3 * x)),
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
export const pdj: (
|
|
||||||
pdjA: number,
|
|
||||||
pdjB: number,
|
|
||||||
pdjC: number,
|
|
||||||
pdjD: number
|
|
||||||
) => Variation = (pdjA, pdjB, pdjC, pdjD) => {
|
|
||||||
return (x, y) => [
|
|
||||||
Math.sin(pdjA * y) - Math.cos(pdjB * x),
|
|
||||||
Math.sin(pdjC * x) - Math.cos(pdjD * y),
|
|
||||||
];
|
|
||||||
};
|
|
@ -81,7 +81,19 @@ const config: Config = {
|
|||||||
prism: {
|
prism: {
|
||||||
theme: prismThemes.oneLight,
|
theme: prismThemes.oneLight,
|
||||||
darkTheme: prismThemes.oneDark,
|
darkTheme: prismThemes.oneDark,
|
||||||
additionalLanguages: ['bash', 'java', 'julia', 'nasm']
|
additionalLanguages: ['bash', 'java', 'julia', 'nasm'],
|
||||||
|
magicComments: [
|
||||||
|
// Remember to extend the default highlight class name as well!
|
||||||
|
{
|
||||||
|
className: 'theme-code-block-highlighted-line',
|
||||||
|
line: 'highlight-next-line',
|
||||||
|
block: {start: 'highlight-start', end: 'highlight-end'},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: 'code-block-hidden',
|
||||||
|
block: {start: 'hidden-start', end: 'hidden-end'}
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
} satisfies Preset.ThemeConfig,
|
} satisfies Preset.ThemeConfig,
|
||||||
plugins: [require.resolve('docusaurus-lunr-search')],
|
plugins: [require.resolve('docusaurus-lunr-search')],
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
import {useColorMode} from "@docusaurus/theme-common";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
srcLight: string;
|
|
||||||
srcDark: string;
|
|
||||||
alt: string;
|
|
||||||
}
|
|
||||||
const DualImage = ({srcLight, srcDark, alt}: Props) => {
|
|
||||||
const {colorMode} = useColorMode();
|
|
||||||
return <img src={colorMode === "dark" ? srcDark : srcLight} alt={alt} />
|
|
||||||
}
|
|
||||||
export default DualImage;
|
|
@ -30,3 +30,10 @@ adapted for Victory charts
|
|||||||
[data-theme='dark'] .VictoryContainer {
|
[data-theme='dark'] .VictoryContainer {
|
||||||
filter: invert(75%) hue-rotate(180deg);
|
filter: invert(75%) hue-rotate(180deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Custom magic comment for Prism - hide parts of the code in display
|
||||||
|
*/
|
||||||
|
.code-block-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user