mirror of
https://github.com/bspeice/speice.io
synced 2024-12-22 08:38:09 -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
|
||||
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:
|
||||
|
||||
@ -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
|
||||
here is correct. As confirmation, the next post will re-create the same image using a different method.
|
||||
</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)
|
||||
$$
|
||||
|
||||
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
|
||||
the general format. For example:
|
||||
|
||||
@ -37,7 +41,7 @@ F_0(x,y) &= \left({x \over 2}, {y \over 2}\right) \\
|
||||
\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":
|
||||
|
||||
$$
|
||||
@ -52,18 +56,18 @@ Our reference image will focus on just four variations:
|
||||
|
||||
### Linear (variation 0)
|
||||
|
||||
This variation returns the $x$ and $y$ coordinates as-is. As mentioned, the Sierpinski Gasket is
|
||||
a fractal flame using only the linear variation:
|
||||
This variation returns the $x$ and $y$ coordinates as-is:
|
||||
|
||||
$$
|
||||
V_0(x,y) = (x,y)
|
||||
$$
|
||||
|
||||
```typescript
|
||||
function linear(x: number, y: number) {
|
||||
return [x, y];
|
||||
}
|
||||
```
|
||||
import linearSrc from '!!raw-loader!../src/linear'
|
||||
|
||||
<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)
|
||||
|
||||
@ -86,18 +90,9 @@ V_{13}(x, y) &= \sqrt{r} \cdot (\text{cos} ( \theta / 2 + \Omega ), \text{sin} (
|
||||
\end{align*}
|
||||
$$
|
||||
|
||||
```typescript
|
||||
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;
|
||||
import juliaSrc from '!!raw-loader!../src/julia'
|
||||
|
||||
return [
|
||||
r * Math.cos(theta / 2 + omega),
|
||||
r * Math.sin(theta / 2 + omega)
|
||||
]
|
||||
}
|
||||
```
|
||||
<CodeBlock language={'typescript'}>{juliaSrc}</CodeBlock>
|
||||
|
||||
### 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))
|
||||
$$
|
||||
|
||||
```typescript
|
||||
function popcorn(coefs: {c: number, f: number}) {
|
||||
return (x: number, y: number) => [
|
||||
x + coefs.c * Math.sin(Math.tan(3 * y)),
|
||||
y + coefs.f * Math.sin(Math.tan(3 * x))
|
||||
]
|
||||
}
|
||||
```
|
||||
import popcornSrc from '!!raw-loader!../src/popcorn'
|
||||
|
||||
<CodeBlock language={'typescript'}>{popcornSrc}</CodeBlock>
|
||||
|
||||
### 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))
|
||||
$$
|
||||
|
||||
```typescript
|
||||
function pdj(a: number, b: number, c: number, d: number) {
|
||||
return (x: number, y: number) => [
|
||||
Math.sin(a * y) - Math.cos(b * x),
|
||||
Math.sin(c * x) - Math.cos(d * y)
|
||||
]
|
||||
}
|
||||
```
|
||||
import pdjSrc from '!!raw-loader!../src/pdj'
|
||||
|
||||
<CodeBlock language={'typescript'}>{pdjSrc}</CodeBlock>
|
||||
|
||||
### 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.
|
||||
*/
|
||||
|
||||
import {Coefs, Transform} from "./types";
|
||||
import { julia, linear, pdj, popcorn } from "./variation";
|
||||
import { Coefs } from './coefs';
|
||||
import { Transform } from './transform';
|
||||
import { linear } from './linear'
|
||||
import { julia } from './julia'
|
||||
import { popcorn } from './popcorn'
|
||||
import { pdj } from './pdj'
|
||||
|
||||
export const identityCoefs: Coefs = {
|
||||
a: 1, b: 0, c: 0,
|
||||
@ -12,53 +16,51 @@ export const identityCoefs: Coefs = {
|
||||
}
|
||||
|
||||
export const xform1Weight = 0.56453495;
|
||||
export const xform1: Transform = {
|
||||
coefs: {
|
||||
a: -1.381068, b: -1.381068, c: 0,
|
||||
d: 1.381068, e: -1.381068, f: 0,
|
||||
},
|
||||
coefsPost: identityCoefs,
|
||||
variations: [[1, julia]],
|
||||
color: 0
|
||||
export const xform1Coefs = {
|
||||
a: -1.381068, b: -1.381068, c: 0,
|
||||
d: 1.381068, e: -1.381068, f: 0,
|
||||
}
|
||||
export const xform1CoefsPost = identityCoefs;
|
||||
export const xform1Variations = [
|
||||
[1, julia]
|
||||
]
|
||||
export const xform1Color = 0;
|
||||
|
||||
const xform2Weight = 0.013135;
|
||||
export const xform2: Transform = {
|
||||
coefs: {
|
||||
a: 0.031393, b: 0.031367, c: 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 xform2Weight = 0.013135;
|
||||
export const xform2Coefs = {
|
||||
a: 0.031393, b: 0.031367, c: 0,
|
||||
d: -0.031367, e: 0.031393, f: 0,
|
||||
}
|
||||
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 xform3: Transform = {
|
||||
coefs: {
|
||||
a: 1.51523, b: -3.048677, c: 0.724135,
|
||||
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 xform3Coefs = {
|
||||
a: 1.51523, b: -3.048677, c: 0.724135,
|
||||
d: 0.740356, e: -1.455964, f: -0.362059,
|
||||
}
|
||||
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 = {
|
||||
coefs: {
|
||||
a: 2, b: 0, c: 0,
|
||||
d: 0, e: 2, f: 0
|
||||
},
|
||||
coefsPost: identityCoefs,
|
||||
variations: [[1, julia]],
|
||||
color: 0
|
||||
export const xformFinalCoefs = {
|
||||
a: 2, b: 0, c: 0,
|
||||
d: 0, e: 2, f: 0
|
||||
}
|
||||
export const xformFinalCoefsPost = identityCoefs;
|
||||
export const xformFinalVariations = [
|
||||
[1, julia]
|
||||
]
|
||||
export const xformFinalColor = 0;
|
||||
|
||||
export const palette =
|
||||
"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: {
|
||||
theme: prismThemes.oneLight,
|
||||
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,
|
||||
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 {
|
||||
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