使用三角函数绘制通过圆的等距平行线
Using Trigonometry to draw equidistant parralleles lines through a circle
如图所示,我需要一个数学公式来计算红色圆点与笛卡尔坐标的等距线。
我猜这不是简单的三角函数...
我的目标是能够计算半个圆周围的笛卡尔点并从中追踪我的线。
使用 p5js,我将使用来自 Perlin 噪声的随机值将其与 sin 或 cos(无论...)混合以从这些点追踪我的线。一开始这是一个数学问题,剩下的对我来说应该很容易,因为我已经有了一个很好的基础,但需要用这个数学来优化。
有什么线索吗?
这是一个角度(极坐标)和笛卡尔坐标之间的转换问题。
这里是一个函数calculateLines(x, y, radius, dist, angle, shift)
,它取圆心坐标、圆半径、直线之间的距离、直线的角度(以弧度为单位)和直线的位移(垂直于它们的方向)。它 returns 一个带有段的数组。一个段由一对坐标决定,即[x1, y1, x2, y2]
.
下面的代码片段允许您使用这些参数并以交互方式查看结果:
function calculateSegments(x, y, radius, dist, angle, shift=0) {
let segments = [];
for (let step = shift - Math.floor((radius + shift) / dist) * dist; step < radius; step += dist) {
let polar = Math.acos(step / radius);
let segment = [
x + Math.cos(angle + polar) * radius,
y + Math.sin(angle + polar) * radius,
x + Math.cos(angle - polar) * radius,
y + Math.sin(angle - polar) * radius
];
segments.push(segment);
}
return segments;
}
// I/O management:
let [inpRadius, inpDistance, inpAngle, inpShift] = document.querySelectorAll("input");
document.addEventListener("input", refresh);
let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
let cx = canvas.width >> 1;
let cy = canvas.height >> 1;
function drawCircle(x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI, false);
ctx.stroke();
}
function drawSegment([x1, y1, x2, y2]) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
function clear() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function refresh() {
// Get current input
let radius = Math.max(1, +inpRadius.value); // sanitise input
let distance = Math.max(1, +inpDistance.value);
let angle = +inpAngle.value * Math.PI / 180; // convert to radians
let shift = +inpShift.value;
// Perform the calculation
let segments = calculateSegments(cx, cy, radius, distance, angle, shift);
// Display result
clear();
drawCircle(cx, cy, radius);
segments.forEach(drawSegment);
}
refresh();
input { width: 5em }
canvas { background: #eee }
<div style="float: left">
Radius of circle: <input type="number" id="radius" value="50" min="1"><br>
Distance between lines: <input type="number" id="distance" value="14" min="1"><br>
Angle of lines (degrees): <input type="number" id="angle" value="120"><br>
Shift: <input type="number" id="shift" value="0"><br>
</div>
<canvas width="180" height="180"></canvas>
鉴于:
(x_cntr, y_cntr) = the center of the circle,
radius = radius of the circle,
dist = distance between lines,
angle = angle of lines relative to the horizontal Ox axis,
offset = distance of first line from the border of the circle:
这是另一个可以完成这项工作的函数。这种方法试图避免在循环中使用余弦和反正弦进行昂贵的计算,并仅用一次昂贵的 sqrt 计算来代替它们。其余的是简单的算术运算(例如乘法和加法)。这个想法是通过给定半径的圆并以原点 (0,0) 为中心计算等距水平线 运行 的简单规范情况下的点的位置,然后旋转和平移坐标以线应相对于水平轴 Ox 定义的角度拟合实际圆边界的点。
function get_points(x_cntr, y_cntr, radius, dist, angle, offset) {
let list_of_points = [];
let n = Math.floor( (2 * radius - offset) / dist ) + 1;
let cos_angle = Math.cos(angle);
let sin_angle = Math.sin(angle);
for (let m = 0; m < n; m = m+1) {
let y = offset + m * dist - radius;
let x = Math.sqrt(radius*radius - y*y);
let point = [
x_cntr + cos_angle * x - sin_angle * y,
y_cntr + sin_angle * x + cos_angle * y
]
list_of_points.push(point);
}
return list_of_points;
}
如图所示,我需要一个数学公式来计算红色圆点与笛卡尔坐标的等距线。 我猜这不是简单的三角函数...
我的目标是能够计算半个圆周围的笛卡尔点并从中追踪我的线。
使用 p5js,我将使用来自 Perlin 噪声的随机值将其与 sin 或 cos(无论...)混合以从这些点追踪我的线。一开始这是一个数学问题,剩下的对我来说应该很容易,因为我已经有了一个很好的基础,但需要用这个数学来优化。
有什么线索吗?
这是一个角度(极坐标)和笛卡尔坐标之间的转换问题。
这里是一个函数calculateLines(x, y, radius, dist, angle, shift)
,它取圆心坐标、圆半径、直线之间的距离、直线的角度(以弧度为单位)和直线的位移(垂直于它们的方向)。它 returns 一个带有段的数组。一个段由一对坐标决定,即[x1, y1, x2, y2]
.
下面的代码片段允许您使用这些参数并以交互方式查看结果:
function calculateSegments(x, y, radius, dist, angle, shift=0) {
let segments = [];
for (let step = shift - Math.floor((radius + shift) / dist) * dist; step < radius; step += dist) {
let polar = Math.acos(step / radius);
let segment = [
x + Math.cos(angle + polar) * radius,
y + Math.sin(angle + polar) * radius,
x + Math.cos(angle - polar) * radius,
y + Math.sin(angle - polar) * radius
];
segments.push(segment);
}
return segments;
}
// I/O management:
let [inpRadius, inpDistance, inpAngle, inpShift] = document.querySelectorAll("input");
document.addEventListener("input", refresh);
let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
let cx = canvas.width >> 1;
let cy = canvas.height >> 1;
function drawCircle(x, y, r) {
ctx.beginPath();
ctx.arc(x, y, r, 0, 2 * Math.PI, false);
ctx.stroke();
}
function drawSegment([x1, y1, x2, y2]) {
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
function clear() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function refresh() {
// Get current input
let radius = Math.max(1, +inpRadius.value); // sanitise input
let distance = Math.max(1, +inpDistance.value);
let angle = +inpAngle.value * Math.PI / 180; // convert to radians
let shift = +inpShift.value;
// Perform the calculation
let segments = calculateSegments(cx, cy, radius, distance, angle, shift);
// Display result
clear();
drawCircle(cx, cy, radius);
segments.forEach(drawSegment);
}
refresh();
input { width: 5em }
canvas { background: #eee }
<div style="float: left">
Radius of circle: <input type="number" id="radius" value="50" min="1"><br>
Distance between lines: <input type="number" id="distance" value="14" min="1"><br>
Angle of lines (degrees): <input type="number" id="angle" value="120"><br>
Shift: <input type="number" id="shift" value="0"><br>
</div>
<canvas width="180" height="180"></canvas>
鉴于:
(x_cntr, y_cntr) = the center of the circle,
radius = radius of the circle,
dist = distance between lines,
angle = angle of lines relative to the horizontal Ox axis,
offset = distance of first line from the border of the circle:
这是另一个可以完成这项工作的函数。这种方法试图避免在循环中使用余弦和反正弦进行昂贵的计算,并仅用一次昂贵的 sqrt 计算来代替它们。其余的是简单的算术运算(例如乘法和加法)。这个想法是通过给定半径的圆并以原点 (0,0) 为中心计算等距水平线 运行 的简单规范情况下的点的位置,然后旋转和平移坐标以线应相对于水平轴 Ox 定义的角度拟合实际圆边界的点。
function get_points(x_cntr, y_cntr, radius, dist, angle, offset) {
let list_of_points = [];
let n = Math.floor( (2 * radius - offset) / dist ) + 1;
let cos_angle = Math.cos(angle);
let sin_angle = Math.sin(angle);
for (let m = 0; m < n; m = m+1) {
let y = offset + m * dist - radius;
let x = Math.sqrt(radius*radius - y*y);
let point = [
x_cntr + cos_angle * x - sin_angle * y,
y_cntr + sin_angle * x + cos_angle * y
]
list_of_points.push(point);
}
return list_of_points;
}