3

Note: I am not 100% sure if this question belongs here, as I dont know if the error is in the programming or in the math, please excuse me and direct me to where to post it

Hi, I am trying to make an infinite zoom fractal effect using P5JS. My approach is to draw the fractal on a graphics, then transform it until one of its "branches" matches the original, then restart, it should look like infinitely going in when I restart the animation

I am calculating the transformation for this basic fractal but somehow it gets off by a few pixels, I don't know where the source of error could be. It is LIKE 4 pixels, but my calculations tell me the match should be exact

so the basic fractal looks like this (a branch of 50px, then recursively rotated 45°(PI/4 rads) and scaled 0.67%)

original fractal

my goal for this stage is to have two renders, the second one transformed such that one branch of it matches the first one, something like this:

expected goal

because the reference point in P5JS is always the top corner, then what I need to do is to rotate by the same amount as the branch, scale the oposite of what the branch shrunk(1/67%), then calculate the translation, but here is the problem. The translation is off and I cannot understand why. I post below the image with scale and rotation only, missing the translation, with the calculations I did. (Note that the original image is rotated but I rotated here to the current frame of reference, so translate in the x axis moves the image to the horizontally and in the y axes moves it vertically)

calculations

So basically the goal of the transform is to place the green point on the blue point, so for the y transform, I need to move -height + X. The angle for the branch is 45°(0.67 rads) and the scaling factor is also 0.6. So my calculationa are that: X = Y - Z. Y = height * 0.67 * sin(PI/4) Z = width / 2 * 0.67 * cos(PI/4)

It seems like a simple calculation, I don't know what could be causing the issue. I realized x's difference is twice as much, I don't know if its because the canvas is twice as wide.

Here is the code. If you uncomment the transform by 4,-2 pixels you will see that the match is exact. In the code you can also see the calculations for the x displacement.

let fractal;
let graphics;

function setup() {
  createCanvas(640, 360);
  angleSlider = createSlider(0, TWO_PI, PI / 4, 0.01);
  scaleSlider = createSlider(0, 0.9, 0.67, 0.01);
  graphics = createGraphics(width, height);
  fractal = {
    render: function(graphics) {
      graphics.line(0, 0, 0, -50);
    },
    prepare: function(graphics) {
      graphics.stroke(0);
      graphics.strokeWeight(2);
      graphics.translate(width * 0.5, height);
    },
    anchors: [{
        rotation: angleSlider.value(),
        scale: 0.67,
        translation: {
          x: 0,
          y: -50
        },
      },
      {
        rotation: -angleSlider.value(),
        scale: 0.67,
        translation: {
          x: 0,
          y: -50
        },
      }
    ],
  };

  graphics.stroke("red");
  graphics.strokeWeight(4);
  graphics.line(0, 0, 0, height);
  graphics.line(0, 0, width, 0);
  graphics.line(0, height, width, height);
  graphics.line(width, 0, width, height);

  graphics.stroke("blue");

  renderFractal(fractal, graphics);
}

function draw() {
  // this is used to have a wider view and debug better, comment to see zoommed in version (does not affect the result)
  scale(0.5)
  translate(width / 2, height / 2)

  // -------

  background(255);
  image(graphics, 0, 0); // small fractal render
  rotate(angleSlider.value())
  scale(1 / 0.67)

  // vertical transform
  translate(0, -height + (height * cos(PI / 4) * 0.67) - (width / 2 * sin(PI / 4) * 0.67));

  // horizontal transform
  translate(width / 2 - ((height * sin(PI / 4) * 0.67) + (width / 2 * 0.67 * cos(PI / 4))), 0);

  // translate the length of the stick
  translate(0, 50);


  //translate(4, -2); // Uncomment this to see it fit

  image(graphics, 0, 0); // big rotated fractal render
}

function renderFractal(fractal, graphics, iterationNumber = 1) {

  if (iterationNumber === 1) {
    fractal.prepare(graphics);

  }
  fractal.render(graphics);
  if (iterationNumber < 10) {
    for (let i = 0; i < fractal.anchors.length; i++) {
      let anchor = fractal.anchors[i];
      graphics.push();
      graphics.translate(anchor.translation.x, anchor.translation.y);

      graphics.rotate(anchor.rotation);
      graphics.scale(anchor.scale);
      renderFractal(fractal, graphics, iterationNumber + 1);
      graphics.pop();
    }
  }
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.min.js"></script>

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.