递归金三角,三角形趋近于哪个点?
Recursive golden triangle, which point does the triangles approach?
我正在尝试制作一个旋转缩放递归金三角。它绘制了一个金色三角形,然后在其中绘制了另一个,依此类推。这很容易,但挑战在于让它放大并围绕三角形接近的点旋转。
为了让它无限放大那个点,我需要想出公式来计算三角形接近哪个点。
运行 此时演示:https://waltari10.github.io/recursive-golden-triangle/index.html
存储库: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
//
// 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()
递归金三角逼近点的计算公式是什么?或者在这种情况下我可以做一些聪明的 hack 吗?
logarithmic spiral的起点由startingPoint(a,b,c)计算,其中a,b,c 是三角形的点:
片段中的三角形不正确'golden triangle'但计算应该是正确的...
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>
我正在尝试制作一个旋转缩放递归金三角。它绘制了一个金色三角形,然后在其中绘制了另一个,依此类推。这很容易,但挑战在于让它放大并围绕三角形接近的点旋转。
为了让它无限放大那个点,我需要想出公式来计算三角形接近哪个点。
运行 此时演示:https://waltari10.github.io/recursive-golden-triangle/index.html
存储库: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
//
// 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()
递归金三角逼近点的计算公式是什么?或者在这种情况下我可以做一些聪明的 hack 吗?
logarithmic spiral的起点由startingPoint(a,b,c)计算,其中a,b,c 是三角形的点:
片段中的三角形不正确'golden triangle'但计算应该是正确的...
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>