Attempt to generalize

This commit is contained in:
2024-11-23 15:26:48 -05:00
parent aba3c9f988
commit e2a0ee1d72
11 changed files with 177 additions and 44 deletions

View File

@ -9,6 +9,7 @@ const functions = [
]
function chaosGame(image) {
var plotter = new Plotter(image.width, image.height);
var [x, y] = [randomBiUnit(), randomBiUnit()];
for (var count = 0; count < iterations; count++) {
@ -16,9 +17,11 @@ function chaosGame(image) {
[x, y] = functions[i](x, y);
if (count > 20) {
plot(x, y, image);
plotter.plot(x, y);
}
}
plotter.paint(image);
}
render(<Canvas renderFn={chaosGame}/>)

View File

@ -1,3 +0,0 @@
export default function randomBiUnit() {
return Math.random() * 2 - 1;
}

View File

@ -157,15 +157,15 @@ Let's turn this into code, one piece at a time.
First, the "bi-unit square" is the range $[-1, 1]$. We can pick a random point like this:
import biunitSource from '!!raw-loader!./biunit'
import randomBiunitSource from '!!raw-loader!../src/randomBiunit'
<CodeBlock language="typescript">{biunitSource}</CodeBlock>
<CodeBlock language="typescript">{randomBiunitSource}</CodeBlock>
Next, we need to choose a random integer from $0$ to $n - 1$:
import randintSource from '!!raw-loader!./randint'
import randomIntegerSource from '!!raw-loader!../src/randomInteger'
<CodeBlock language="typescript">{randintSource}</CodeBlock>
<CodeBlock language="typescript">{randomIntegerSource}</CodeBlock>
Finally, implementing the `plot` function. Web browsers have a [Canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API)
we can use for 2D graphics. In our case, the plot function will take an $(x,y)$ coordinate and plot it by

View File

@ -1,32 +1,40 @@
export default function plot(x: number, y: number, image: ImageData) {
// Translate (x,y) coordinates to pixel coordinates.
// The display range we care about is x=[0, 1], y=[0, 1],
// so our pixelX and pixelY coordinates are easy to calculate:
const pixelX = Math.floor(x * image.width);
const pixelY = Math.floor(y * image.height);
export function imageIndex(x: number, y: number, width: number, stride: number): number {
return y * (width * stride) + x * 4;
}
// If we have an (x,y) coordinate outside the display range,
// skip it
if (
pixelX < 0 ||
pixelX > image.width ||
pixelY < 0 ||
pixelY > image.height
) {
return;
export class Plotter {
private readonly pixels: Array<boolean>;
constructor(private readonly width: number, private readonly height: number) {
this.pixels = new Array(width * height).fill(false);
}
// ImageData is an array that contains four bytes per pixel
// (one for each of the red, green, blue, and alpha values).
// The (pixelX, pixelY) coordinates are used to find where
// in the image we need to write.
const index = pixelY * (image.width * 4) + pixelX * 4;
public plot(x: number, y: number) {
// Translate (x,y) coordinates to pixel coordinates.
// The display range we care about is x=[0, 1], y=[0, 1],
// so our pixelX and pixelY coordinates are easy to calculate:
const pixelX = Math.floor(x * this.width);
const pixelY = Math.floor(y * this.height);
// Set the pixel to black by writing a 0 to the first three
// bytes (red, green, blue), and 256 to the last byte (alpha),
// starting at our index:
image.data[index] = 0;
image.data[index + 1] = 0;
image.data[index + 2] = 0;
image.data[index + 3] = 0xff;
// Translate the pixel coordinates into an index
const pixelIndex = imageIndex(pixelX, pixelY, this.width, 1);
// If the index is valid, enable that pixel
if (0 <= pixelIndex && pixelIndex < this.pixels.length) {
this.pixels[pixelIndex] = true;
}
}
public paint(image: ImageData) {
// "Paint" all our pixels by setting their value to black
for (var pixelIndex = 0; pixelIndex < this.pixels.length; pixelIndex++) {
if (this.pixels[pixelIndex]) {
const imageIndex = pixelIndex * 4;
image.data[imageIndex] = 0; // red
image.data[imageIndex + 1] = 0; // green
image.data[imageIndex + 2] = 0; // blue
image.data[imageIndex + 3] = 0xff; // alpha
}
}
}
}

View File

@ -1,3 +0,0 @@
export default function randomInteger(min: number, max: number) {
return Math.floor(Math.random() * (max - min)) + min;
}

View File

@ -1,13 +1,13 @@
import React from 'react';
import randomBiUnit from './biunit';
import plot from './plot';
import randomInteger from './randint';
import { randomBiUnit } from '../src/randomBiunit';
import { Plotter } from './plot';
import { randomInteger } from '../src/randomInteger';
import Canvas from './Canvas';
const Scope = {
React,
plot,
Plotter,
randomBiUnit,
randomInteger,
Canvas