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

满足曲率约束的三次Bezier曲线控制点筛选问题

三次Bezier曲线曲率约束优化问题

任务描述

需构造最大曲率不超过$K_{max}$的三次Bezier曲线(含4个控制点),曲率计算公式为:
$$k = \frac{|y''|}{(1+y'2){1.5}}$$
已知固定控制点$p_0=(0,0)$、$p_3=(0.3,0)$,$p_1$、$p_2$为可调整控制点。当前采用网格扫描方案:利用对称性仅在右上象限选取$p_1$,遍历所有可能的$p_2$,检查曲线是否满足曲率约束,保存符合条件的控制点组合。

现有实现代码

import numpy as np
import scipy as sc
from matplotlib import pyplot as plt

def bezzier_curve(p0, p1, p2, p3, t):
    b0 = b_in_calc(3, 0, t) * np.transpose(p0)
    b1 = b_in_calc(3, 1, t) * np.transpose(p1)
    b2 = b_in_calc(3, 2, t) * np.transpose(p2)
    b3 = b_in_calc(3, 3, t) * np.transpose(p3)
    b = b0 + b1 + b2 + b3
    return b


def b_in_calc(n, i, t):
    b = sc.special.binom(n, i)
    t1 = np.power(1-t, n-i)
    t2 = np.power(t, i)
    return b*t1*t2


def numerical_deriv(y, x):
    # finding numerical derivative of the finction
    dx = np.gradient(x)
    dy = np.gradient(y)
    d = dy/dx
    return d


k_max_allowed = 5
d = 0.3
p0 = np.zeros([1, 2])
p3 = np.array([[0.3, 0]])
p1 = np.zeros([1, 2])
p2 = np.zeros([1, 2])
t = np.linspace(0, 1, 10000)
P1_space = np.linspace(0, d/2, num=40)
P2_xspace = np.linspace(0, d, endpoint=False, num=40)
P2_yspace = np.linspace(-d/2, d/2, 40)

output_name = 'desired_coordinates_K_max_5.txt'

condition = 0 # if we started writing P1 or not
condition1 = 0 # if we already wrote at least 1 P2 point

with open(output_name, 'w',encoding='utf-8') as f:
    for i in range(1, len(P1_space)):
        p1[0, 0] = P1_space[i]
        for j in range(1, len(P1_space)):
            p1[0, 1] = P1_space[j]            
            
            for n in range(1, len(P2_xspace)):
                p2[0,0] = P2_xspace[n]
                for m in range(len(P2_yspace)):
                    p2[0,1] = P2_yspace[m]
                        
                    # create bezier curve
                    bezz = bezzier_curve(p0, p1, p2, p3, t)
                    x_vec = bezz[0, :]
                    y_vec = bezz[1, :]
                        
                    # interpolate points to spread them
                    x_interp = np.linspace(0, d, len(t), endpoint=True)
                    y_interp = np.interp(x_interp, x_vec, y_vec)  
                        
                    # derive and find curvature vector and max k
                    y_deriv = numerical_deriv(y_interp, x_interp)
                    y_deriv2 = numerical_deriv(y_deriv, x_interp)
                    k_vec = y_deriv2/(1 + y_deriv**2)**1.5
                    k_max = np.amax(k_vec)
                        
                    # check if meets condition, if so write it to .txt file
                    if k_max <= k_max_allowed:
                        if condition == 0:
                            f.write('P1:' + str(P1_space[int(i)]) + ',' + str(P1_space[int(j)]) + '\n')
                            condition = 1
                        if condition1 ==0:
                            f.write('P2:')
                            condition1 = 1
                        f.write(str(P2_xspace[n]) + ',' + str(P2_yspace[m]) + '|')
                        
            condition = 0
            condition1 = 0
        f.write('\n')
f.close()

plt.text(5,5 , 'Complete', fontsize = 22)
plt.xlim(0, 15)
plt.ylim(0, 10)
plt.show()

遇到的问题

读取保存的控制点组合并验证时,部分组合生成的曲线曲率超过设定的$K_{max}$。即使改用解析求导,问题仍存在,部分控制点会导致曲线左侧出现大曲率区域。

改进建议

1. 修正曲率计算的绝对值处理

曲率是标量,需取绝对值。当前代码中k_vec未计算绝对值,导致仅考虑正的二阶导数对应的曲率,漏掉了负二阶导数的大曲率情况(比如左侧区域)。修改为:

k_vec = np.abs(y_deriv2)/(1 + y_deriv**2)**1.5
k_max = np.amax(k_vec)

2. 替换数值求导为解析导数(更稳定)

三次Bezier曲线的导数有解析表达式,避免插值和数值求导的误差:

  • 一阶导数(对参数t):
    $$B'(t) = 3(1-t)^2(p_1-p_0) + 6(1-t)t(p_2-p_1) + 3t^2(p_3-p_2)$$
  • 二阶导数(对参数t):
    $$B''(t) = 6(1-t)(p_2-2p_1+p_0) + 6t(p_3-2p_2+p_1)$$
  • 转换为对x的导数:
    $$\frac{dy}{dx} = \frac{dy/dt}{dx/dt}, \quad \frac{d2y}{dx2} = \frac{d/dt(dy/dx)}{dx/dt}$$
    直接基于t计算这些值,避免x插值带来的误差,尤其是曲线x非单调时。

3. 限制p2的选取范围

  • 排除x非单调的组合:当$dx/dt=0$时,曲线出现垂直切线或回折,曲率会趋于无穷大。提前检查$dx/dt$在$t∈[0,1]$内是否有零点,若有则直接跳过该控制点组合。
  • 利用对称性约束:若目标是对称曲线,可强制$p_2=(0.3-p_1.x, -p_1.y)$,缩小搜索范围;非对称场景也可限制$p_2$的y值范围,使其与$p_1$的y绝对值相当,避免曲线起伏过大。

4. 精准捕捉曲率极值

  • 仅靠采样点的最大值可能漏掉真实极值,可使用数值优化方法(如scipy.optimize.minimize_scalar)寻找$|k(t)|$在$t∈[0,1]$内的最大值,确保准确检测到最大曲率。
  • 增加关键区域采样密度:在$dx/dt$变化大的区域(即曲线斜率变化快的地方)增加t的采样点,提高极值检测概率。

5. 添加后验证步骤

在保存控制点组合前,用更高精度的方法(解析导数+极值优化)重新验证一次,确认最大曲率严格小于$K_{max}$后再写入文件,避免误判。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 01:15:54