Mass formatting, fix mobile display, fix issues with image wrap-around

This commit is contained in:
2024-12-15 21:19:09 -05:00
parent 1ce6137c17
commit 456c3a66e5
41 changed files with 1026 additions and 817 deletions

View File

@ -1,51 +1,52 @@
import TeX from "@matejmazur/react-katex";
import {Coefs} from "../src/coefs";
import { Coefs } from "../src/transform";
import styles from "../src/css/styles.module.css";
export interface Props {
title: String;
isPost: boolean;
coefs: Coefs;
setCoefs: (coefs: Coefs) => void;
resetCoefs: () => void;
title: String;
isPost: boolean;
coefs: Coefs;
setCoefs: (coefs: Coefs) => void;
resetCoefs: () => void;
}
export const CoefEditor = ({title, isPost, coefs, setCoefs, resetCoefs}: Props) => {
const resetButton = <button className={styles.inputReset} onClick={resetCoefs}>Reset</button>
return (
<div className={styles.inputGroup} style={{display: 'grid', gridTemplateColumns: '1fr 1fr 1fr'}}>
<p className={styles.inputTitle} style={{gridColumn: '1/-1'}}>{title} {resetButton}</p>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\alpha</TeX> : 'a'}: {coefs.a}</p>
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.a}
onInput={e => setCoefs({...coefs, a: Number(e.currentTarget.value)})}/>
</div>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\beta</TeX> : 'b'}: {coefs.b}</p>
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.b}
onInput={e => setCoefs({...coefs, b: Number(e.currentTarget.value)})}/>
</div>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\gamma</TeX> : 'c'}: {coefs.c}</p>
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.c}
onInput={e => setCoefs({...coefs, c: Number(e.currentTarget.value)})}/>
</div>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\delta</TeX> : 'd'}: {coefs.d}</p>
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.d}
onInput={e => setCoefs({...coefs, d: Number(e.currentTarget.value)})}/>
</div>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\epsilon</TeX> : 'e'}: {coefs.e}</p>
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.e}
onInput={e => setCoefs({...coefs, e: Number(e.currentTarget.value)})}/>
</div>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\zeta</TeX> : 'f'}: {coefs.f}</p>
<input type={'range'} min={-2} max={2} step={0.01} value={coefs.f}
onInput={e => setCoefs({...coefs, f: Number(e.currentTarget.value)})}/>
</div>
</div>
)
}
export const CoefEditor = ({ title, isPost, coefs, setCoefs, resetCoefs }: Props) => {
const resetButton = <button className={styles.inputReset} onClick={resetCoefs}>Reset</button>;
return (
<div className={styles.inputGroup} style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr" }}>
<p className={styles.inputTitle} style={{ gridColumn: "1/-1" }}>{title} {resetButton}</p>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\alpha</TeX> : "a"}: {coefs.a}</p>
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.a}
onInput={e => setCoefs({ ...coefs, a: Number(e.currentTarget.value) })} />
</div>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\beta</TeX> : "b"}: {coefs.b}</p>
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.b}
onInput={e => setCoefs({ ...coefs, b: Number(e.currentTarget.value) })} />
</div>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\gamma</TeX> : "c"}: {coefs.c}</p>
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.c}
onInput={e => setCoefs({ ...coefs, c: Number(e.currentTarget.value) })} />
</div>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\delta</TeX> : "d"}: {coefs.d}</p>
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.d}
onInput={e => setCoefs({ ...coefs, d: Number(e.currentTarget.value) })} />
</div>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\epsilon</TeX> : "e"}: {coefs.e}</p>
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.e}
onInput={e => setCoefs({ ...coefs, e: Number(e.currentTarget.value) })} />
</div>
<div className={styles.inputElement}>
<p>{isPost ? <TeX>\zeta</TeX> : "f"}: {coefs.f}</p>
<input type={"range"} min={-2} max={2} step={0.01} value={coefs.f}
onInput={e => setCoefs({ ...coefs, f: Number(e.currentTarget.value) })} />
</div>
</div>
);
};

View File

@ -1,68 +1,68 @@
import {useContext, useEffect, useState} from "react";
import {Transform} from "../src/transform";
import * as params from "../src/params"
import {PainterContext} from "../src/Canvas"
import {chaosGameFinal} from "./chaosGameFinal"
import {VariationEditor, VariationProps} from "./VariationEditor"
import {applyTransform} from "../src/applyTransform";
import {buildBlend} from "./buildBlend";
import { useContext, useEffect, useState } from "react";
import { Transform } from "../src/transform";
import * as params from "../src/params";
import { PainterContext } from "../src/Canvas";
import { chaosGameFinal } from "./chaosGameFinal";
import { VariationEditor, VariationProps } from "./VariationEditor";
import { applyTransform } from "../src/applyTransform";
import { buildBlend } from "./buildBlend";
export default function FlameBlend() {
const {width, height, setPainter} = useContext(PainterContext);
const { width, height, setPainter } = useContext(PainterContext);
const xform1VariationsDefault: VariationProps = {
linear: 0,
julia: 1,
popcorn: 0,
pdj: 0,
}
const [xform1Variations, setXform1Variations] = useState(xform1VariationsDefault)
const resetXform1Variations = () => setXform1Variations(xform1VariationsDefault);
const xform1VariationsDefault: VariationProps = {
linear: 0,
julia: 1,
popcorn: 0,
pdj: 0
};
const [xform1Variations, setXform1Variations] = useState(xform1VariationsDefault);
const resetXform1Variations = () => setXform1Variations(xform1VariationsDefault);
const xform2VariationsDefault: VariationProps = {
linear: 1,
julia: 0,
popcorn: 1,
pdj: 0
}
const [xform2Variations, setXform2Variations] = useState(xform2VariationsDefault)
const resetXform2Variations = () => setXform2Variations(xform2VariationsDefault);
const xform2VariationsDefault: VariationProps = {
linear: 1,
julia: 0,
popcorn: 1,
pdj: 0
};
const [xform2Variations, setXform2Variations] = useState(xform2VariationsDefault);
const resetXform2Variations = () => setXform2Variations(xform2VariationsDefault);
const xform3VariationsDefault: VariationProps = {
linear: 0,
julia: 0,
popcorn: 0,
pdj: 1
}
const [xform3Variations, setXform3Variations] = useState(xform3VariationsDefault)
const resetXform3Variations = () => setXform3Variations(xform3VariationsDefault);
const xform3VariationsDefault: VariationProps = {
linear: 0,
julia: 0,
popcorn: 0,
pdj: 1
};
const [xform3Variations, setXform3Variations] = useState(xform3VariationsDefault);
const resetXform3Variations = () => setXform3Variations(xform3VariationsDefault);
const identityXform: Transform = (x, y) => [x, y];
const identityXform: Transform = (x, y) => [x, y];
useEffect(() => {
const transforms: [number, Transform][] = [
[params.xform1Weight, applyTransform(params.xform1Coefs, buildBlend(params.xform1Coefs, xform1Variations))],
[params.xform2Weight, applyTransform(params.xform2Coefs, buildBlend(params.xform2Coefs, xform2Variations))],
[params.xform3Weight, applyTransform(params.xform3Coefs, buildBlend(params.xform3Coefs, xform3Variations))]
]
useEffect(() => {
const transforms: [number, Transform][] = [
[params.xform1Weight, applyTransform(params.xform1Coefs, buildBlend(params.xform1Coefs, xform1Variations))],
[params.xform2Weight, applyTransform(params.xform2Coefs, buildBlend(params.xform2Coefs, xform2Variations))],
[params.xform3Weight, applyTransform(params.xform3Coefs, buildBlend(params.xform3Coefs, xform3Variations))]
];
const gameParams = {
width,
height,
transforms,
final: identityXform
}
setPainter(chaosGameFinal(gameParams));
}, [xform1Variations, xform2Variations, xform3Variations]);
const gameParams = {
width,
height,
transforms,
final: identityXform
};
setPainter(chaosGameFinal(gameParams));
}, [xform1Variations, xform2Variations, xform3Variations]);
return (
<>
<VariationEditor title={"Transform 1"} variations={xform1Variations} setVariations={setXform1Variations}
resetVariations={resetXform1Variations}/>
<VariationEditor title={"Transform 2"} variations={xform2Variations} setVariations={setXform2Variations}
resetVariations={resetXform2Variations}/>
<VariationEditor title={"Transform 3"} variations={xform3Variations} setVariations={setXform3Variations}
resetVariations={resetXform3Variations}/>
</>
)
return (
<>
<VariationEditor title={"Transform 1"} variations={xform1Variations} setVariations={setXform1Variations}
resetVariations={resetXform1Variations} />
<VariationEditor title={"Transform 2"} variations={xform2Variations} setVariations={setXform2Variations}
resetVariations={resetXform2Variations} />
<VariationEditor title={"Transform 3"} variations={xform3Variations} setVariations={setXform3Variations}
resetVariations={resetXform3Variations} />
</>
);
}

View File

@ -1,46 +1,46 @@
import {useContext, useEffect, useState} from "react";
import {Coefs} from "../src/coefs"
import { useContext, useEffect, useState } from "react";
import { Coefs } from "../src/transform";
import * as params from "../src/params";
import {PainterContext} from "../src/Canvas"
import {buildBlend} from "./buildBlend";
import {chaosGameFinal} from "./chaosGameFinal"
import {VariationEditor, VariationProps} from "./VariationEditor";
import {CoefEditor} from "./CoefEditor";
import {applyPost, applyTransform} from "../src/applyTransform";
import { PainterContext } from "../src/Canvas";
import { buildBlend } from "./buildBlend";
import { chaosGameFinal } from "./chaosGameFinal";
import { VariationEditor, VariationProps } from "./VariationEditor";
import { CoefEditor } from "./CoefEditor";
import { applyPost, applyTransform } from "../src/applyTransform";
export default function FlameFinal() {
const {width, height, setPainter} = useContext(PainterContext);
const { width, height, setPainter } = useContext(PainterContext);
const [xformFinalCoefs, setXformFinalCoefs] = useState<Coefs>(params.xformFinalCoefs);
const resetXformFinalCoefs = () => setXformFinalCoefs(params.xformFinalCoefs);
const [xformFinalCoefs, setXformFinalCoefs] = useState<Coefs>(params.xformFinalCoefs);
const resetXformFinalCoefs = () => setXformFinalCoefs(params.xformFinalCoefs);
const xformFinalVariationsDefault: VariationProps = {
linear: 0,
julia: 1,
popcorn: 0,
pdj: 0
}
const [xformFinalVariations, setXformFinalVariations] = useState<VariationProps>(xformFinalVariationsDefault);
const resetXformFinalVariations = () => setXformFinalVariations(xformFinalVariationsDefault);
const xformFinalVariationsDefault: VariationProps = {
linear: 0,
julia: 1,
popcorn: 0,
pdj: 0
};
const [xformFinalVariations, setXformFinalVariations] = useState<VariationProps>(xformFinalVariationsDefault);
const resetXformFinalVariations = () => setXformFinalVariations(xformFinalVariationsDefault);
const [xformFinalCoefsPost, setXformFinalCoefsPost] = useState<Coefs>(params.xformFinalCoefsPost);
const resetXformFinalCoefsPost = () => setXformFinalCoefsPost(params.xformFinalCoefsPost);
const [xformFinalCoefsPost, setXformFinalCoefsPost] = useState<Coefs>(params.xformFinalCoefsPost);
const resetXformFinalCoefsPost = () => setXformFinalCoefsPost(params.xformFinalCoefsPost);
useEffect(() => {
const finalBlend = buildBlend(xformFinalCoefs, xformFinalVariations);
const finalXform = applyPost(xformFinalCoefsPost, applyTransform(xformFinalCoefs, finalBlend));
useEffect(() => {
const finalBlend = buildBlend(xformFinalCoefs, xformFinalVariations);
const finalXform = applyPost(xformFinalCoefsPost, applyTransform(xformFinalCoefs, finalBlend));
setPainter(chaosGameFinal({width, height, transforms: params.xforms, final: finalXform}));
}, [xformFinalCoefs, xformFinalVariations, xformFinalCoefsPost]);
setPainter(chaosGameFinal({ width, height, transforms: params.xforms, final: finalXform }));
}, [xformFinalCoefs, xformFinalVariations, xformFinalCoefsPost]);
return (
<>
<CoefEditor title={"Final Transform"} isPost={false} coefs={xformFinalCoefs} setCoefs={setXformFinalCoefs}
resetCoefs={resetXformFinalCoefs}/>
<VariationEditor title={"Final Transform Variations"} variations={xformFinalVariations}
setVariations={setXformFinalVariations} resetVariations={resetXformFinalVariations}/>
<CoefEditor title={"Final Transform Post"} isPost={true} coefs={xformFinalCoefsPost}
setCoefs={setXformFinalCoefsPost} resetCoefs={resetXformFinalCoefsPost}/>
</>
)
return (
<>
<CoefEditor title={"Final Transform"} isPost={false} coefs={xformFinalCoefs} setCoefs={setXformFinalCoefs}
resetCoefs={resetXformFinalCoefs} />
<VariationEditor title={"Final Transform Variations"} variations={xformFinalVariations}
setVariations={setXformFinalVariations} resetVariations={resetXformFinalVariations} />
<CoefEditor title={"Final Transform Post"} isPost={true} coefs={xformFinalCoefsPost}
setCoefs={setXformFinalCoefsPost} resetCoefs={resetXformFinalCoefsPost} />
</>
);
}

View File

@ -1,46 +1,46 @@
import {useContext, useEffect, useState} from "react";
import {Coefs} from "../src/coefs"
import {Transform} from "../src/transform";
import { useContext, useEffect, useState } from "react";
import { applyTransform } from "../src/applyTransform";
import { Coefs, Transform } from "../src/transform";
import * as params from "../src/params";
import {PainterContext} from "../src/Canvas"
import {chaosGameFinal, Props as ChaosGameFinalProps} from "./chaosGameFinal"
import {CoefEditor} from "./CoefEditor"
import {applyPost, applyTransform} from "@site/blog/2024-11-15-playing-with-fire/src/applyTransform";
import { PainterContext } from "../src/Canvas";
import { chaosGameFinal, Props as ChaosGameFinalProps } from "./chaosGameFinal";
import { CoefEditor } from "./CoefEditor";
import { transformPost } from "./post";
export default function FlamePost() {
const {width, height, setPainter} = useContext(PainterContext);
const { width, height, setPainter } = useContext(PainterContext);
const [xform1CoefsPost, setXform1CoefsPost] = useState<Coefs>(params.xform1CoefsPost);
const resetXform1CoefsPost = () => setXform1CoefsPost(params.xform1CoefsPost);
const [xform1CoefsPost, setXform1CoefsPost] = useState<Coefs>(params.xform1CoefsPost);
const resetXform1CoefsPost = () => setXform1CoefsPost(params.xform1CoefsPost);
const [xform2CoefsPost, setXform2CoefsPost] = useState<Coefs>(params.xform2CoefsPost);
const resetXform2CoefsPost = () => setXform2CoefsPost(params.xform2CoefsPost);
const [xform2CoefsPost, setXform2CoefsPost] = useState<Coefs>(params.xform2CoefsPost);
const resetXform2CoefsPost = () => setXform2CoefsPost(params.xform2CoefsPost);
const [xform3CoefsPost, setXform3CoefsPost] = useState<Coefs>(params.xform3CoefsPost);
const resetXform3CoefsPost = () => setXform3CoefsPost(params.xform3CoefsPost);
const [xform3CoefsPost, setXform3CoefsPost] = useState<Coefs>(params.xform3CoefsPost);
const resetXform3CoefsPost = () => setXform3CoefsPost(params.xform3CoefsPost);
const identityXform: Transform = (x, y) => [x, y];
const identityXform: Transform = (x, y) => [x, y];
const gameParams: ChaosGameFinalProps = {
width,
height,
transforms: [
[params.xform1Weight, applyPost(xform1CoefsPost, applyTransform(params.xform1Coefs, params.xform1Variations))],
[params.xform2Weight, applyPost(xform2CoefsPost, applyTransform(params.xform2Coefs, params.xform2Variations))],
[params.xform3Weight, applyPost(xform3CoefsPost, applyTransform(params.xform3Coefs, params.xform3Variations))],
],
final: identityXform
}
useEffect(() => setPainter(chaosGameFinal(gameParams)), [xform1CoefsPost, xform2CoefsPost, xform3CoefsPost]);
const gameParams: ChaosGameFinalProps = {
width,
height,
transforms: [
[params.xform1Weight, transformPost(applyTransform(params.xform1Coefs, params.xform1Variations), xform1CoefsPost)],
[params.xform2Weight, transformPost(applyTransform(params.xform2Coefs, params.xform2Variations), xform2CoefsPost)],
[params.xform3Weight, transformPost(applyTransform(params.xform3Coefs, params.xform3Variations), xform3CoefsPost)]
],
final: identityXform
};
useEffect(() => setPainter(chaosGameFinal(gameParams)), [xform1CoefsPost, xform2CoefsPost, xform3CoefsPost]);
return (
<>
<CoefEditor title={"Transform 1 Post"} isPost={true} coefs={xform1CoefsPost} setCoefs={setXform1CoefsPost}
resetCoefs={resetXform1CoefsPost}/>
<CoefEditor title={"Transform 2 Post"} isPost={true} coefs={xform2CoefsPost} setCoefs={setXform2CoefsPost}
resetCoefs={resetXform2CoefsPost}/>
<CoefEditor title={"Transform 3 Post"} isPost={true} coefs={xform3CoefsPost} setCoefs={setXform3CoefsPost}
resetCoefs={resetXform3CoefsPost}/>
</>
)
return (
<>
<CoefEditor title={"Transform 1 Post"} isPost={true} coefs={xform1CoefsPost} setCoefs={setXform1CoefsPost}
resetCoefs={resetXform1CoefsPost} />
<CoefEditor title={"Transform 2 Post"} isPost={true} coefs={xform2CoefsPost} setCoefs={setXform2CoefsPost}
resetCoefs={resetXform2CoefsPost} />
<CoefEditor title={"Transform 3 Post"} isPost={true} coefs={xform3CoefsPost} setCoefs={setXform3CoefsPost}
resetCoefs={resetXform3CoefsPost} />
</>
);
}

View File

@ -1,45 +1,45 @@
import styles from "../src/css/styles.module.css"
import styles from "../src/css/styles.module.css";
export interface VariationProps {
linear: number;
julia: number;
popcorn: number;
pdj: number;
linear: number;
julia: number;
popcorn: number;
pdj: number;
}
export interface Props {
title: String;
variations: VariationProps;
setVariations: (variations: VariationProps) => void;
resetVariations: () => void;
title: String;
variations: VariationProps;
setVariations: (variations: VariationProps) => void;
resetVariations: () => void;
}
export const VariationEditor = ({title, variations, setVariations, resetVariations}: Props) => {
const resetButton = <button className={styles.inputReset} onClick={resetVariations}>Reset</button>
export const VariationEditor = ({ title, variations, setVariations, resetVariations }: Props) => {
const resetButton = <button className={styles.inputReset} onClick={resetVariations}>Reset</button>;
return (
<div className={styles.inputGroup} style={{display: 'grid', gridTemplateColumns: '1fr 1fr'}}>
<p className={styles.inputTitle} style={{gridColumn: '1/-1'}}>{title} {resetButton}</p>
<div className={styles.inputElement}>
<span>Linear: {variations.linear}</span>
<input type={'range'} min={0} max={1} step={0.01} style={{width: '100%'}} value={variations.linear}
onInput={e => setVariations({...variations, linear: Number(e.currentTarget.value)})}/>
</div>
<div className={styles.inputElement}>
<span>Julia: {variations.julia}</span>
<input type={'range'} min={0} max={1} step={0.01} style={{width: '100%'}} value={variations.julia}
onInput={e => setVariations({...variations, julia: Number(e.currentTarget.value)})}/>
</div>
<div className={styles.inputElement}>
<span>Popcorn: {variations.popcorn}</span>
<input type={'range'} min={0} max={1} step={0.01} style={{width: '100%'}} value={variations.popcorn}
onInput={e => setVariations({...variations, popcorn: Number(e.currentTarget.value)})}/>
</div>
<div className={styles.inputElement}>
<span>PDJ: {variations.pdj}</span>
<input type={'range'} min={0} max={1} step={0.01} style={{width: '100%'}} value={variations.pdj}
onInput={e => setVariations({...variations, pdj: Number(e.currentTarget.value)})}/>
</div>
</div>
)
}
return (
<div className={styles.inputGroup} style={{ display: "grid", gridTemplateColumns: "1fr 1fr" }}>
<p className={styles.inputTitle} style={{ gridColumn: "1/-1" }}>{title} {resetButton}</p>
<div className={styles.inputElement}>
<span>Linear: {variations.linear}</span>
<input type={"range"} min={0} max={1} step={0.01} style={{ width: "100%" }} value={variations.linear}
onInput={e => setVariations({ ...variations, linear: Number(e.currentTarget.value) })} />
</div>
<div className={styles.inputElement}>
<span>Julia: {variations.julia}</span>
<input type={"range"} min={0} max={1} step={0.01} style={{ width: "100%" }} value={variations.julia}
onInput={e => setVariations({ ...variations, julia: Number(e.currentTarget.value) })} />
</div>
<div className={styles.inputElement}>
<span>Popcorn: {variations.popcorn}</span>
<input type={"range"} min={0} max={1} step={0.01} style={{ width: "100%" }} value={variations.popcorn}
onInput={e => setVariations({ ...variations, popcorn: Number(e.currentTarget.value) })} />
</div>
<div className={styles.inputElement}>
<span>PDJ: {variations.pdj}</span>
<input type={"range"} min={0} max={1} step={0.01} style={{ width: "100%" }} value={variations.pdj}
onInput={e => setVariations({ ...variations, pdj: Number(e.currentTarget.value) })} />
</div>
</div>
);
};

View File

@ -1,17 +1,17 @@
import {Coefs} from "../src/coefs";
import {VariationProps} from "./VariationEditor";
import {linear} from "../src/linear";
import {julia} from "../src/julia";
import {popcorn} from "../src/popcorn";
import {pdj} from "../src/pdj";
import {pdjParams} from "../src/params";
import {VariationBlend} from "../src/blend";
import { Coefs } from "../src/transform";
import { VariationProps } from "./VariationEditor";
import { linear } from "../src/linear";
import { julia } from "../src/julia";
import { popcorn } from "../src/popcorn";
import { pdj } from "../src/pdj";
import { pdjParams } from "../src/params";
import { Blend } from "../src/blend";
export function buildBlend(coefs: Coefs, variations: VariationProps): VariationBlend {
return [
[variations.linear, linear],
[variations.julia, julia],
[variations.popcorn, popcorn(coefs)],
[variations.pdj, pdj(pdjParams)]
]
export function buildBlend(coefs: Coefs, variations: VariationProps): Blend {
return [
[variations.linear, linear],
[variations.julia, julia],
[variations.popcorn, popcorn(coefs)],
[variations.pdj, pdj(pdjParams)]
];
}

View File

@ -1,37 +1,51 @@
// hidden-start
import { randomBiUnit } from "../src/randomBiUnit";
import { randomChoice } from "../src/randomChoice";
import { plotBinary as plot } from "../src/plotBinary"
import {Transform} from "../src/transform";
import {Props as ChaosGameWeightedProps} from "../1-introduction/chaosGameWeighted";
import { plotBinary as plot } from "../src/plotBinary";
import { Transform } from "../src/transform";
import { Props as WeightedProps } from "../1-introduction/chaosGameWeighted";
const quality = 0.5;
const step = 1000;
// hidden-end
export type Props = ChaosGameWeightedProps & {
final: Transform,
export type Props = WeightedProps & {
final: Transform,
}
export function* chaosGameFinal({width, height, transforms, final}: Props) {
let image = new ImageData(width, height);
let [x, y] = [randomBiUnit(), randomBiUnit()];
const iterations = width * height * quality;
for (let i = 0; i < iterations; i++) {
const [_, transform] = randomChoice(transforms);
[x, y] = transform(x, y);
export function* chaosGameFinal(
{
width,
height,
transforms,
final
}: Props
) {
let img =
new ImageData(width, height);
let [x, y] = [
randomBiUnit(),
randomBiUnit()
];
// highlight-start
const [finalX, finalY] = final(x, y);
// highlight-end
const pixels = width * height;
const iterations = quality * pixels;
for (let i = 0; i < iterations; i++) {
const [_, transform] =
randomChoice(transforms);
[x, y] = transform(x, y);
if (i > 20)
// highlight-start
plot(finalX, finalY, image);
// highlight-end
// highlight-start
const [finalX, finalY] = final(x, y);
// highlight-end
if (i % step === 0)
yield image;
}
if (i > 20)
// highlight-start
plot(finalX, finalY, img);
// highlight-end
yield image;
if (i % step === 0)
yield img;
}
yield img;
}

View File

@ -34,7 +34,7 @@ This leads us to the first big innovation of the Fractal Flame algorithm: adding
after the affine transform. These functions are called "variations":
$$
F_i(x, y) = V_j(a_i \cdot x + b_i \cdot y + c_i, d_i \cdot x + e_i \cdot y + f_i)
F_i(x, y) = V_j(a_i x + b_i y + c_i, d_i x + e_i y + f_i)
$$
import variationSource from '!!raw-loader!../src/variation'
@ -96,7 +96,7 @@ Some variations rely on knowing the transform's affine coefficients; they're cal
For the popcorn variation, we use $c$ and $f$:
$$
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\ \text{sin}(\text{tan }3y), y + f\ \text{sin}(\text{tan }3x))
$$
import popcornSrc from '!!raw-loader!../src/popcorn'
@ -109,8 +109,8 @@ Some variations have extra parameters; they're called "parametric variations."
For the PDJ variation, there are four extra parameters we can choose:
$$
p_1 = \text{pdj.a} \hspace{0.2cm} p_2 = \text{pdj.b} \hspace{0.2cm} p_3 = \text{pdj.c} \hspace{0.2cm} p_4 = \text{pdj.d} \\
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))
p_1 = \text{pdj.a} \hspace{0.1cm} p_2 = \text{pdj.b} \hspace{0.1cm} p_3 = \text{pdj.c} \hspace{0.1cm} p_4 = \text{pdj.d} \\
V_{24} = (\text{sin}(p_1 y) - \text{cos}(p_2 x), \text{sin}(p_3 x) - \text{cos}(p_4 y))
$$
import pdjSrc from '!!raw-loader!../src/pdj'
@ -124,7 +124,7 @@ Each variation receives the same $x$ and $y$ inputs, and we add together each va
We'll also give each variation a weight ($v_{ij}$) that changes how much it contributes to the result:
$$
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)
F_i(x,y) = \sum_{j} v_{ij} V_j(x, y)
$$
The formula looks intimidating, but it's not hard to implement:

View File

@ -1,7 +1,11 @@
// hidden-start
import {Coefs} from "../src/coefs";
import {Transform} from "../src/transform";
import {applyCoefs} from "../src/coefs";
import { applyCoefs, Coefs, Transform } from "../src/transform";
// hidden-end
export const transformPost = (transform: Transform, coefs: Coefs): Transform =>
(x, y) => applyCoefs(...transform(x, y), coefs)
export const transformPost = (
transform: Transform,
coefs: Coefs
): Transform =>
(x, y) => {
[x, y] = transform(x, y);
return applyCoefs(x, y, coefs);
}