You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同心圆外圆切线延长线与外圆交点坐标求解(JS Canvas)

同心圆切线交点求解(Canvas绘图用)

已知圆心在原点(0,0)的两个同心圆,外圆半径R,内圆半径r,外圆上一点A(x₀,y₀),求从A出发的两条内圆切线延长后与外圆的交点B、C坐标。

数学推导步骤

  1. 切线斜率求解
    设切线斜率为k,直线方程为y - y₀ = k(x - x₀),圆心到直线的距离等于内圆半径r,据此列出方程:

    |y₀ - kx₀| / √(k² + 1) = r
    

    整理为关于k的二次方程:

    (x₀² - r²)k² - 2x₀y₀k + (R² - x₀² - r²) = 0
    

    利用二次方程求根公式k = [2x₀y₀ ± √Δ]/[2(x₀² - r²)],其中判别式化简后为:

    Δ = 4r²(R² - x₀²)
    

    代入后可得到两个斜率k₁、k₂,对应两条切线。

  2. 求外圆交点B、C
    对每个切线斜率k,利用韦达定理求直线与外圆的另一交点(A点已在圆上):

    • x坐标:x_B = [-2k(y₀ - kx₀)/(1 + k²)] - x₀
    • y坐标:y_B = k * x_B + (y₀ - kx₀)
      同理可得C点坐标(x_C, y_C)。

JavaScript实现代码(适配Canvas)

function getTangentIntersections(Ax, Ay, R, r) {
    // 容错:自动将A点归一化到外圆上
    const distSq = Ax*Ax + Ay*Ay;
    if (Math.abs(distSq - R*R) > 1e-6) {
        const scale = R / Math.sqrt(distSq);
        Ax *= scale;
        Ay *= scale;
    }

    const x0 = Ax, y0 = Ay;
    const a = x0*x0 - r*r;
    const b = -2 * x0 * y0;
    const c = (R*R - x0*x0) - r*r;
    const delta = b*b - 4*a*c;

    // 无切线情况(r >= R)
    if (delta < -1e-6) return null;
    const sqrtDelta = Math.sqrt(Math.max(delta, 0));

    // 计算交点的通用函数
    const getPoint = (k) => {
        const denom = 1 + k*k;
        const numeratorX = -2*k*(y0 - k*x0);
        const x = (numeratorX / denom) - x0;
        const y = k*x + (y0 - k*x0);
        return {
            x: parseFloat(x.toFixed(6)),
            y: parseFloat(y.toFixed(6))
        };
    };

    let points = [];
    // 处理斜率存在的情况
    if (Math.abs(a) > 1e-6) {
        const k1 = (-b + sqrtDelta) / (2*a);
        const k2 = (-b - sqrtDelta) / (2*a);
        points.push(getPoint(k1));
        points.push(getPoint(k2));
    } else {
        // 处理垂直于x轴的切线(斜率不存在)
        const yVal = Math.sqrt(R*R - x0*x0);
        points.push({x: x0, y: y0 === yVal ? -yVal : yVal});
        // 计算另一条斜率存在的切线交点
        const k = -c/b;
        points.push(getPoint(k));
        // 去重
        points = points.filter((p, idx, arr) => 
            idx === arr.findIndex(q => Math.abs(p.x - q.x) < 1e-6 && Math.abs(p.y - q.y) < 1e-6)
        );
    }

    return points;
}

// Canvas绘图示例
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const R = 100;
const r = 50;
const A = {x: 100, y: 0};

const intersections = getTangentIntersections(A.x, A.y, R, r);

// 绘制同心圆
ctx.beginPath();
ctx.arc(0, 0, R, 0, Math.PI*2);
ctx.stroke();
ctx.beginPath();
ctx.arc(0, 0, r, 0, Math.PI*2);
ctx.stroke();

// 标记A点
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.arc(A.x, A.y, 3, 0, Math.PI*2);
ctx.fill();

// 绘制切线与交点
if (intersections) {
    intersections.forEach(point => {
        ctx.fillStyle = 'blue';
        ctx.beginPath();
        ctx.arc(point.x, point.y, 3, 0, Math.PI*2);
        ctx.fill();
        ctx.beginPath();
        ctx.moveTo(A.x, A.y);
        ctx.lineTo(point.x, point.y);
        ctx.strokeStyle = 'green';
        ctx.stroke();
    });
}

注意事项

  • 浮点精度:用1e-6作为误差阈值,避免浮点运算导致的逻辑错误。
  • 特殊场景:处理了切线垂直于x轴(斜率不存在)的情况,同时覆盖了r=0(内圆退化为原点)、r=R(无切线)等边界情况。

内容的提问来源于stack exchange,提问作者JudgeRoyBean

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 06:13:20