Recursive golden triangle, which point does the triangles approach?

Viewed 140

I am trying to make a rotating zooming recursive golden triangle. It draws a golden triangle, then it draws another one inside it and so on. This was easy, but the challenge is making it zoom in and rotate around the point that the triangles are approaching.

To make it zoom in on that point infinitely I need to come up with the formula to calculate which point the triangles are approaching.

enter image description here

Running demo at this point: https://waltari10.github.io/recursive-golden-triangle/index.html

Repository: https://github.com/Waltari10/recursive-golden-triangle

/**
 * 
 * @param {float[]} pivot
 * @param {float} angle 
 * @param {float[]} point 
 * @returns {float[]} point 
 */
function rotatePoint(pivot, angle, point)
{
  const s = Math.sin(angle);
  const c = Math.cos(angle);


  const pointOriginX = point[0] - pivot[0];
  const pointOriginY = point[1] - pivot[1];

  // rotate point
  const xNew = (pointOriginX * c) - (pointOriginY * s);
  const yNew = (pointOriginX * s) + (pointOriginY * c);

  const newPoint = [
    pivot[0] + xNew,
    pivot[1] + yNew,
  ]

  return newPoint;
}

// https://www.onlinemath4all.com/90-degree-clockwise-rotation.html
// https://stackoverflow.com/questions/2259476/rotating-a-point-about-another-point-2d
// Position is half way between points B and C 72 and 72, because AB/BC is golden ratio
function drawGoldenTriangle(pos, height, rotation, color = [0,255,0,255], pivot) {

// golden triangle degrees 72, 72, 36
// golden gnomon 36, 36, 108
// AB/BC is the golden ratio number
// https://www.mathsisfun.com/algebra/sohcahtoa.html

  const baseLength = (Math.tan(degToRad(18)) * height) * 2;

  const pointA = rotatePoint(pos, rotation, [pos[0], pos[1] - height]); // sharpest angle
  const pointB = rotatePoint(pos, rotation, [pos[0] - (baseLength / 2), pos[1]]); 
  const pointC = rotatePoint(pos, rotation, [pos[0] + (baseLength / 2), pos[1]]);


  drawTriangle(pointA, pointB, pointC, [0,255,0,255]);

}

let i = 0;

function drawRecursiveGoldenTriangle(pos, height, rotation, pivot) {

  
  drawGoldenTriangle(pos, height, rotation, [0,255,0,255], pivot);
  i++;

  if (i > 10) {
    return;
  }


  const hypotenuseLength = height / Math.cos(degToRad(18));
  const baseLength = (Math.tan(degToRad(18)) * height) * 2;
  const goldenRatio = hypotenuseLength / baseLength;

  const newHeight = height / goldenRatio;

  const newRotation = rotation - 108 * Math.PI/180

  const newPointC = rotatePoint(pos, rotation, [pos[0] + (baseLength / 2), pos[1]]);

  // Go half baselength up CA direction from pointC to get new position
  const newHypotenuseLength = baseLength;
  const newBaseLength = newHypotenuseLength / goldenRatio;

  let newPosXRelative = Math.cos(newRotation) * (newBaseLength / 2)
  let newPosYRelative = Math.sin(newRotation) * (newBaseLength / 2)
  
  const newPos = [newPointC[0] + newPosXRelative, newPointC[1] + newPosYRelative];

  drawRecursiveGoldenTriangle(newPos, newHeight, newRotation, [0,255,0,255], pivot); 

  
}

let triangleHeight = height - 50;

let pivotPoint = [(width/2),(height/2) -50];
let triangleLocation = [width/2, height/2 + 300];


let triangleRotation = 0;

function loop() {
  i = 0;

  const startTime = Date.now()
  wipeCanvasData();

  // triangleHeight++; 
  // triangleRotation = triangleRotation + 0.005;


  // drawX(pivotPoint)
  // drawX(triangleLocation)

  
  // Pivot point determines the point which the recursive golden 
  // triangle rotates around. Should be the point that triangles 
  // approach.
  drawRecursiveGoldenTriangle(triangleLocation, triangleHeight, triangleRotation, pivotPoint); 

  updateCanvas()
  const renderTime = Date.now() - startTime
  timeDelta = renderTime < targetFrameDuration ? targetFrameDuration : renderTime
  this.setTimeout(() => {
    loop()
  }, targetFrameDuration - renderTime)
}

loop()

What would be the formula to calculate the point that recursive golden triangle is approaching? Or is there some clever hack I could do in this situation?

1 Answers

The starting point of the logarithmic spiral is calculated by startingPoint(a,b,c) where a,b,c are the points of your triangle:

enter image description here

The triangle in the snippet is not a proper 'golden triangle' but the calculations should be correct...

const distance = (p1, p2) => Math.hypot(p2.x - p1.x, p2.y - p1.y);

const intersection = (p1, p2, p3, p4) => {
  const l1A = (p2.y - p1.y) / (p2.x - p1.x);
  const l1B = p1.y - l1A * p1.x;

  const l2A = (p4.y - p3.y) / (p4.x - p3.x);
  const l2B = p3.y - l2A * p3.x;
  
  const x = (l2B - l1B) / (l1A - l2A);
  const y = x * l1A + l1B;
  
  return {x, y};
}

const startingPoint = (a, b, c) => {
  const ac = distance(a, c);
  const ab = distance(a, b);
  const bc = distance(b, c);
  // Law of cosines
  const alpha = Math.acos((ab * ab + ac * ac - bc * bc) / (2 * ab * ac));
  const gamma = Math.acos((ac * ac + bc * bc - ab * ab) / (2 * ac * bc));
  const delta = Math.PI - alpha / 2 - gamma;
  // Law of sines
  const cd = ac * Math.sin(alpha / 2) / Math.sin(delta);
  const d = {
    x: cd * (b.x - c.x) / bc + c.x,
    y: cd * (b.y - c.y) / bc + c.y
  };
  const e = {
    x: (a.x + c.x) / 2,
    y: (a.y + c.y) / 2
  };
  const f = {
    x: (a.x + b.x) / 2,
    y: (a.y + b.y) / 2,
  };
  return intersection(c, f, d, e);
};

d3.select('svg').append('path')
  .attr('d', 'M 100,50 L150,200 H 50 Z')
  .style('fill', 'none')
  .style('stroke', 'blue')
  
const point = startingPoint({x: 50, y: 200},{x: 100, y: 50},{x: 150, y: 200});  
console.log(point);

d3.select('svg').append('circle')
  .attr('cx', point.x)  
  .attr('cy', point.y)
  .attr('r', 5)
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="200" height="400"></svg>

Related