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

基于起点、终点与初始方向的0-90度圆弧绘制实现方法

《铁路大亨3》定端点定初始方向0-90°圆弧实现方案

这个需求是典型的单约束圆弧拟合问题,几何上存在唯一符合要求的解,不需要迭代,直接用解析公式即可算出所有绘制参数。

输入参数约定

  • 起点坐标:P0 = (x0, y0)
  • 终点坐标:P1 = (x1, y1)
  • 起点处切线方向:dir = (dx, dy),需提前归一化为单位长度向量
  • 约束:圆弧圆心角范围为0°~90°,起点切线与dir完全重合

核心推导逻辑

圆的两个基础性质可以直接定位圆心:

  1. 过圆上一点的切线的垂线必然经过圆心,即圆心一定在过P0、与dir垂直的法线上
  2. 圆心到P0、P1的距离相等,均为圆弧半径R

基于以上性质直接列方程求解:

  1. 记P0指向P1的向量为v = (vx, vy) = (x1-x0, y1-y0)
  2. 垂直于dir的单位法向量有两个方向候选:n1=(-dy, dx)、n2=(dy, -dx),分别对应切线左右两侧
  3. 圆心可以表示为参数形式:C = P0 + R * n(n为选中的单位法向量,R为正半径)
  4. 代入|C-P1|=R的距离约束,利用n是单位向量的特性消去二次项,直接解出半径:
    R = (vx² + vy²) / (2 * (vx*nx + vy*ny))
    
    其中nx/ny是选中法向量的x/y分量
  5. 解出R后即可得到圆心坐标,再通过两个半径向量P0-C、P1-C的点积计算圆心角θ,筛选出θ在0°~90°区间的合法解即可。

边界判定规则:

  • 若法向量代入后分母为0,说明P1在P0的初始切线上,对应α=0°场景,圆弧退化为P0到P1的直线段
  • 若算出的R为负数,或圆心角θ>90°,说明当前法向量方向错误,换另一个候选法向量重算即可
  • α=90°场景下,合法解对应的圆心角恰好为90°,即标准四分之一圆弧

可直接落地的伪代码

import math

def build_rail_arc(p0: tuple[float, float], p1: tuple[float, float], dir: tuple[float, float]):
    x0, y0 = p0
    x1, y1 = p1
    dx, dy = dir
    vx = x1 - x0
    vy = y1 - y0
    EPS = 1e-6
    PI_HALF = math.pi / 2

    # 两点重合直接返回空
    if abs(vx) < EPS and abs(vy) < EPS:
        return None

    # 两个候选法向量
    n_candidates = [(-dy, dx), (dy, -dx)]
    selected = None

    for nx, ny in n_candidates:
        denom = 2 * (vx * nx + vy * ny)
        # 分母为0对应直线场景
        if abs(denom) < EPS:
            continue
        r = (vx**2 + vy**2) / denom
        if r <= EPS:
            continue
        # 计算圆心坐标
        cx = x0 + r * nx
        cy = y0 + r * ny
        # 计算圆心角
        vec0_x = x0 - cx
        vec0_y = y0 - cy
        vec1_x = x1 - cx
        vec1_y = y1 - cy
        dot = vec0_x * vec1_x + vec0_y * vec1_y
        cos_theta = dot / (r * r)
        cos_theta = max(-1.0, min(1.0, cos_theta)) # 修正浮点误差
        theta = math.acos(cos_theta)
        # 筛选0-90度范围内的合法解
        if -EPS <= theta <= PI_HALF + EPS:
            # 计算圆弧起始角、扫掠方向
            start_angle = math.atan2(vec0_y, vec0_x)
            # 叉积判断弯向(扫掠方向)
            cross = dx * vy - dy * vx
            sweep_dir = 1 if cross > 0 else -1
            selected = {
                "type": "arc",
                "center": (cx, cy),
                "radius": r,
                "start_angle": start_angle,
                "sweep_angle": theta * sweep_dir
            }
            break

    # 无合法圆弧则返回直线(α=0场景)
    if selected is None:
        selected = {
            "type": "line",
            "start": p0,
            "end": p1
        }
    return selected

绘制适配说明

  • 所有浮点计算预留1e-6的精度容差,避免边界场景下计算错误
  • 返回的圆弧参数可以直接传入绝大多数2D绘图接口(Canvas、GDI+、Cocos/Unity图形组件等),注意不同接口对角度正负(顺时针/逆时针)的定义差异,调整sweep_dir的取值即可
  • 通用场景、α=0直线场景、α=90直角四分之一圆场景均能通过该逻辑正确生成

内容的提问来源于stack exchange,提问作者PRR S2 6-8-6 turbine engine

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 21:21:26