mirror of
				https://github.com/bspeice/speice.io
				synced 2025-10-30 17:10:31 -04:00 
			
		
		
		
	Refactor to use a step function
This commit is contained in:
		| @ -28,7 +28,7 @@ export const Canvas: React.FC<{ f: renderFn }> = ({ f }) => { | |||||||
|     } |     } | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   return <canvas ref={canvasRef} width={600} height={600} />; |   return <canvas ref={canvasRef} width={400} height={400} />; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export function randomInteger(min: number, max: number) { | export function randomInteger(min: number, max: number) { | ||||||
|  | |||||||
| @ -10,7 +10,7 @@ function plot(x: number, y: number, image: ImageData) { | |||||||
|   //  pixelY = Math.floor((y + 1) * image.height / 2) |   //  pixelY = Math.floor((y + 1) * image.height / 2) | ||||||
|   // |   // | ||||||
|   // However, that produces a mirror image (across both X and Y) |   // However, that produces a mirror image (across both X and Y) | ||||||
|   // from the paper. We'll invert X and Y to compensate. |   // from the paper. We'll negate X and Y to compensate. | ||||||
|   // Second, because the gasket solution only contains points in |   // Second, because the gasket solution only contains points in | ||||||
|   // the range [0, 1), the naive plot above would waste 75% of |   // the range [0, 1), the naive plot above would waste 75% of | ||||||
|   // the pixels available. We'll keep the shift by 1 (to compensate |   // the pixels available. We'll keep the shift by 1 (to compensate | ||||||
|  | |||||||
| @ -17,7 +17,7 @@ function r(x: number, y: number) { | |||||||
| } | } | ||||||
|  |  | ||||||
| function theta(x: number, y: number) { | function theta(x: number, y: number) { | ||||||
|   return Math.atan2(x, y); |   return Math.atan2(y, x); | ||||||
| } | } | ||||||
|  |  | ||||||
| function omega(): number { | function omega(): number { | ||||||
| @ -93,6 +93,18 @@ export function weightedChoice<T>(choices: [number, T][]) { | |||||||
|   throw "unreachable"; |   throw "unreachable"; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export class Flame { | ||||||
|  |   x: number = Math.random() * 2 - 1; | ||||||
|  |   y: number = Math.random() * 2 - 1; | ||||||
|  |  | ||||||
|  |   constructor(public readonly transforms: [number, Transform][]) {} | ||||||
|  |  | ||||||
|  |   step() { | ||||||
|  |     const transform = weightedChoice(this.transforms); | ||||||
|  |     [this.x, this.y] = transform.apply(this.x, this.y); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| export function plot(x: number, y: number, image: ImageData) { | export function plot(x: number, y: number, image: ImageData) { | ||||||
|   const pixelX = Math.floor(((x + 2) * image.width) / 4); |   const pixelX = Math.floor(((x + 2) * image.width) / 4); | ||||||
|   const pixelY = Math.floor(((y + 2) * image.height) / 4); |   const pixelY = Math.floor(((y + 2) * image.height) / 4); | ||||||
| @ -114,23 +126,13 @@ export function plot(x: number, y: number, image: ImageData) { | |||||||
|   image.data[index + 3] = 0xff; |   image.data[index + 3] = 0xff; | ||||||
| } | } | ||||||
|  |  | ||||||
| export class Flame { | export function render(flame: Flame, quality: number, image: ImageData) { | ||||||
|   constructor(public readonly transforms: [number, Transform][]) {} |   const iterations = quality * image.width * image.height; | ||||||
|  |  | ||||||
|   render(quality: number, image: ImageData) { |   for (var i = 0; i < iterations; i++) { | ||||||
|     var x = Math.random() * 2 - 1; |     flame.step(); | ||||||
|     var y = Math.random() * 2 - 1; |     if (i > 20) { | ||||||
|  |       plot(flame.x, flame.y, image); | ||||||
|     const iter = quality * (image.width * image.height); |  | ||||||
|     for (var i = 0; i < iter; i++) { |  | ||||||
|       const transform = weightedChoice(this.transforms); |  | ||||||
|  |  | ||||||
|       // Play the chaos game |  | ||||||
|       [x, y] = transform.apply(x, y); |  | ||||||
|  |  | ||||||
|       if (i > 20) { |  | ||||||
|         plot(x, y, image); |  | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @ -185,5 +187,5 @@ export function renderBaseline(image: ImageData) { | |||||||
|     [transform3Weight, transform3], |     [transform3Weight, transform3], | ||||||
|   ]); |   ]); | ||||||
|  |  | ||||||
|   flame.render(1, image); |   render(flame, 1, image); | ||||||
| } | } | ||||||
|  | |||||||
| @ -7,6 +7,7 @@ import { | |||||||
|   julia, |   julia, | ||||||
|   popcorn, |   popcorn, | ||||||
|   pdj, |   pdj, | ||||||
|  |   render, | ||||||
|   transform1Coefs, |   transform1Coefs, | ||||||
|   transform1Weight, |   transform1Weight, | ||||||
|   transform2Coefs, |   transform2Coefs, | ||||||
| @ -75,5 +76,6 @@ export function renderPost(image: ImageData) { | |||||||
|     [transform2Weight, transform2], |     [transform2Weight, transform2], | ||||||
|     [transform3Weight, transform3], |     [transform3Weight, transform3], | ||||||
|   ]); |   ]); | ||||||
|   flame.render(1, image); |  | ||||||
|  |   render(flame, 1, image); | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,8 +13,7 @@ import { | |||||||
|   transform3Coefs, |   transform3Coefs, | ||||||
|   transform3Pdj, |   transform3Pdj, | ||||||
|   transform3Weight, |   transform3Weight, | ||||||
|   weightedChoice, |   render, | ||||||
|   plot, |  | ||||||
| } from "./2a-variations"; | } from "./2a-variations"; | ||||||
| import { TransformPost, transform2Post } from "./2b-post"; | import { TransformPost, transform2Post } from "./2b-post"; | ||||||
|  |  | ||||||
| @ -26,22 +25,9 @@ export class FlameFinal extends Flame { | |||||||
|     super(transforms); |     super(transforms); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   render(quality: number, image: ImageData) { |   step() { | ||||||
|     var x = Math.random() * 2 - 1; |     super.step(); | ||||||
|     var y = Math.random() * 2 - 1; |     [this.x, this.y] = this.final.apply(this.x, this.y); | ||||||
|  |  | ||||||
|     const iter = quality * (image.width * image.height); |  | ||||||
|     for (var i = 0; i < iter; i++) { |  | ||||||
|       const transform = weightedChoice(this.transforms); |  | ||||||
|       [x, y] = transform.apply(x, y); |  | ||||||
|  |  | ||||||
|       // This line is the only thing that changes: |  | ||||||
|       [x, y] = this.final.apply(x, y); |  | ||||||
|  |  | ||||||
|       if (i > 20) { |  | ||||||
|         plot(x, y, image); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -82,5 +68,5 @@ export function renderFinal(image: ImageData) { | |||||||
|     transformFinal |     transformFinal | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   flame.render(1, image); |   render(flame, 1, image); | ||||||
| } | } | ||||||
|  | |||||||
| @ -14,10 +14,14 @@ export default function () { | |||||||
|   }); |   }); | ||||||
|   return ( |   return ( | ||||||
|     <Layout> |     <Layout> | ||||||
|       <Canvas f={gasket} /> |       <div> | ||||||
|       <Canvas f={renderBaseline} /> |         <Canvas f={gasket} /> | ||||||
|       <Canvas f={renderPost} /> |         <Canvas f={renderBaseline} /> | ||||||
|       <Canvas f={renderFinal} /> |       </div> | ||||||
|  |       <div> | ||||||
|  |         <Canvas f={renderPost} /> | ||||||
|  |         <Canvas f={renderFinal} /> | ||||||
|  |       </div> | ||||||
|     </Layout> |     </Layout> | ||||||
|   ); |   ); | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user