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%)
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:
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)
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>


