圆内任意一点和角度到圆周的距离

问题描述 投票:0回答:2

从技术上讲,这是一道数学题,但我不明白如何将其转化为代码。

我有一个圆心C,它的半径r,以及圆内的点A和B。我需要找到距离 AD,因此 B 仅用于角度。所以这意味着用从 3 个点计算出的角度和边来求解三角形 ACD。 换句话说,我想找到从圆内任意点到圆周的距离,有一个角度。

我试过的伪代码:

float dis(float a_x, float a_y, float b_x, float b_y, float c_x, float c_y, float r) {
  float ab_x = a_x - b_x;
  float ab_y = a_y - b_y;

  float ac_x = a_x - c_x;
  float ac_y = a_y - c_y;

  float ab_a = atan(ab_y, ab_x);
  float ac_a = atan(ac_y, ac_x);
  float dc_a = pi - ac_a - ab_a;

  return (sin(dc_a) * r) / sin(ab_a);
}

这产生错误的结果可能是因为不止一个错误。 如何正确地做到这一点?

我在数学交流中读到它,最终了解到它是一个简单的三角形,但是在编程上下文中我找不到能回答我的问题。

math language-agnostic trigonometry
2个回答
0
投票

您可以按以下方式处理:

首先,我们可以平移(“移动”)给定的点,使𝐶 的坐标为 (0, 0)。所以我们从 𝐴 和 𝐵 中减去 𝐶。这不影响解决方案。所以现在我们只有 𝐴 和 𝐵 作为输入。

其次,我们可以缩放问题,使圆的半径为 1。这意味着我们将 𝐴 和 𝐵 除以当前半径(|𝐴|)。

通过𝐴和𝐵的线可以写成𝐴+𝑛(𝐵−𝐴),其中𝑛是变量。让我们调用 𝑊=𝐵−𝐴,然后对 𝑊 进行归一化,使其大小为 1。然后我们必须满足以下等式才能确定 𝑚 的值:

𝐷 = 𝐴 + 𝑚𝑊(𝐷 位于通过 𝐴 和 𝐵 的线上),并且
|𝐷| = 1(𝐷位于单位圆上)

为了简化计算,我们可以将第二个等式替换为:

|𝐷|² = 1

代入𝐷,我们得到:

|𝐴 + 𝑚𝑊|² = 1
(𝐴𝑥 + 𝑚𝑊𝑥)² + (𝐴𝑦 + 𝑚𝑊𝑦)² = 1
𝐴𝑥² +2𝑚𝐴𝑥𝑊𝑥 +𝑚意义 𝐴𝑥² +𝐴𝑦² +2𝑚(𝐴𝑥𝑊𝑥 +𝐴𝑦𝑊
𝑦) +𝑚²(𝑊𝑥² +𝑊𝑦²)=1 (𝑊𝑥² + 𝑊𝑦²)𝑚² + 2(𝐴𝑥𝑊𝑥 + 𝐴𝑦𝑊
𝑦)𝑚 + 𝐴𝑥𝑊𝑥 + 𝐴𝑦𝑊𝑦)𝑚 + 𝐴𝑥𝑊𝑥1 = 0 这是一个二次方程。求解它会给出 1 或 2 个可能的 𝑚 值,而 0 始终是其中之一。如果有一个非零的,我们想要得到那个,并取它的绝对值(因为距离永远不会是负数)。

最后,因为我们将问题缩放到单位圆,所以需要将 𝑚 的找到值缩放回原始问题。

这是 JavaScript 中的一个实现:

// Utility functions to work with 2D vectors: function sub(u, v) { return [u[0] - v[0], u[1] - v[1]]; } function add(u, v) { return [u[0] + v[0], u[1] + v[1]]; } function mul(u, m) { // Scalar multiplication return [m * u[0], m * u[1]]; } function size(u) { return Math.sqrt(u[0] * u[0] + u[1] * u[1]); } function norm(u) { // Resize vector to size 1 return mul(u, 1 / size(u)); } function solveQuadratic(a, b, c) { // To solve ax² + bx + c = 0 const discr = b * b - 4 * a * c; if (discr < 0) return []; // No real solutions if (discr == 0) return [-b / 2 / a]; // One real solution const root = Math.sqrt(discr); return [(-b - root) / 2 / a, (-b + root) / 2 / a]; // Two } function solve(a, b, c) { // Translate problem to C at (0, 0): this does not influence the result a = sub(a, c); b = sub(b, c); // Scale problem to Unit circle const r = size(a); a = mul(a, 1/r); b = mul(b, 1/r); // Define W as the direction vector of the line A-B, with size 1. const w = norm(sub(b, a)); // Solve equation to find m, such that D = A+mW and |D|² is 1, i.e. // |A+mW|² = 1, or // (Ax+mWx)²+(Ay+mWy)² = 1, or // (Ax)² + 2mAxWx + m²(Wx)² + (Ay)² + 2mAyWy + m²(Wy)² = 1, or // (Ax)²+(Ay)² - 1 + 2m(AxWx+AyWy) + m²((Wx)²+(Wy)²) = 0 // Solve by m: const roots = solveQuadratic(w[0] * w[0] + w[1] * w[1], 2 * (a[0] * w[0] + a[1] * w[1]), a[0] * a[0] + a[1] * a[1] - 1); // Get the solution where m is not zero (account for floating point precision): const m = Math.abs(roots[0]) > 1e-10 ? roots[0] : roots.at(-1); // Scale the solution back to the original size return m * r; // This is a signed number. For distance, take absolute value } // Demo const dist = solve([3, 5], [6, 6], [5, 10]); console.log(dist);
这是一个交互式版本,其中点𝐴和𝐶是固定的,但𝐵对应于鼠标指针所在的位置。然后你可以看到你移动鼠标指针的距离,以及相应的线段。

// Utility functions to work with 2D vectors: function sub(a, b) { return [a[0] - b[0], a[1] - b[1]]; } function add(a, b) { return [a[0] + b[0], a[1] + b[1]]; } function mul(a, m) { // Scalar multiplication return [m * a[0], m * a[1]]; } function size(a) { return Math.sqrt(a[0] * a[0] + a[1] * a[1]); } function norm(a) { // Resize vector to size 1 return mul(a, 1 / size(a)); } function solveQuadratic(a, b, c) { const discr = b * b - 4 * a * c; if (discr < 0) return []; // No real solutions if (discr == 0) return [-b / 2 / a]; // One real solution const root = Math.sqrt(discr); return [(-b - root) / 2 / a, (-b + root) / 2 / a]; // Two } function solve(a, b, c) { // Translate problem to C at (0, 0): this does not influence the result a = sub(a, c); b = sub(b, c); // Scale problem to Unit circle const r = size(a); a = mul(a, 1/r); b = mul(b, 1/r); // Define G as the direction vector of the line A-B, with size 1. const g = norm(sub(b, a)); // Solve equation to find m, such that D = A+mG and |D|² is 1, i.e. // |A+mG|² = 1, or // (Ax+mGx)²+(Ay+mGy)² = 1, or // (Ax)² + 2mAxGx + m²(Gx)² + (Ay)² + 2mAyGy + m²(Gy)² = 1, or // (Ax)²+(Ay)² - 1 + 2m(AxGx+AyGy) + m²((Gx)²+(Gy)²) = 0 // Solve by m: const roots = solveQuadratic(g[0] * g[0] + g[1] * g[1], 2 * (a[0] * g[0] + a[1] * g[1]), a[0] * a[0] + a[1] * a[1] - 1); // Get the solution where m is not zero (account for floating point precision): const m = Math.abs(roots[0]) > 1e-10 ? roots[0] : roots.at(-1); // Scale the solution back to the original size return m * r; // This is a signed number. For distance, take absolute value } // I/O handling and actual call of the solve function. const canvas = document.querySelector("canvas"); const ctx = canvas.getContext("2d"); const output = document.querySelector("span"); function drawCircle(c, a) { ctx.beginPath(); ctx.arc(...c, size(sub(c, a)), 0, 2 * Math.PI); ctx.stroke(); } function drawLine(a, d) { ctx.beginPath(); ctx.moveTo(...a); ctx.lineTo(...d); ctx.stroke(); } function clear() { ctx.clearRect(0, 0, canvas.width, canvas.height); } document.addEventListener("mousemove", refresh); function refresh(e) { // For demo we fix points a and c. b is determined by pointer position const c = [200, 90]; const a = [150, 30]; clear(); drawCircle(c, a); if (!e) return; // No coordinates for b provided. // Convert mouse pointer to coordinates for b (relative to the canvas) const b = [e.clientX - canvas.offsetLeft, e.clientY - canvas.offsetTop]; const dist = solve(a, b, c); // <<<< EXECUTE THE ALGORITHM >>>> output.textContent = Math.abs(dist); // Output the result // For drawing the line segment, calculate d using a, b and dist const d = add(a, mul(norm(sub(b, a)), dist)); drawLine(a, d); } refresh();
<canvas height="170" width="500"></canvas> <div>Size of line segment: <span></span></div>

在三角形 ACD 上使用

0
投票
,我们得到:

CD² = AC² + AD² - 2 AC AD cos(CAB)

我们知道
CD = r

AC = r

,因为C是圆心,A和D在圆上。
我们可以使用
点积的欧几里德公式

,也称为“余弦相似度”来计算

cos(CAB)

cos(CAB) = <AB, AC> / (AB AC) /* where <AB,AC> is dot-product */ /* and (AB AC) is product of norms */

调用
z = AD
我们正在寻找的距离,并调用

γ = cos(CAB)

我们计算的余弦,方程变为:
r² = r² + z² - 2rγz

r² 抵消,由于 z 不为零,我们可以将其简化为:
z = 2rγ

这可以变成代码:
def distance_ad(ax,ay, bx,by, cx,cy, r):
    γ = ((bx-ax)*(cx-ax) + (by-ay)*(cy-ay)) / (r * sqrt((bx-ax)² + (by-ay)²))
    return 2 * r * γ


© www.soinside.com 2019 - 2024. All rights reserved.