我一直觉得,极坐标下"隐式方程"这四个字是数学绘图工具最装糊涂的地方。很多人一看到 f(θ,r)=0,下意识就认定这是 r=f(θ) 的另一种写法——显式嘛,套公式采样点、连成线就完事了。但这个想法在两个地方碎得特别彻底:一是同一个 θ 方向可以穿出好几个 r,函数关系不存在;二是某些曲线在你采样最密的那个角度附近突然钻出个尖头或过原点,肉眼根本追不上。
最近我在自用的绘图小工具 FuncPlotCalc 里把这个事彻底做了一遍:输入任意极坐标隐式方程 f(θ,r)=0,输出稳定、闭合、可缩放的曲线。整个过程不算复杂,核心策略再直白不过——固定 θ,把二维求根降成一维求根。但真正把这些根"找全""找对",陆陆续续踩了不少坑。这篇文章把我实际用的思路、完整代码、验证案例和坑记录下来,给想自己写极坐标隐式曲线绘图器的朋友一条能直接抄的近路。
1. 为什么极坐标隐式方程不能像显式函数那样直接画
1.1 什么样的方程算"极坐标隐式方程"
先对齐定义。极坐标里的显式方程长这样:r = 1 + cos(θ),给定一个 θ,算术式直接把 r 算出来,然后直角坐标 x = r·cos(θ)、y = r·sin(θ) 就是图上的点。整个过程没有任何歧义。
隐式方程就不同,它把 θ 和 r 松松散散地塞进一个等式里,比如:
r² - a²·cos(2θ) = 0,伯努利双纽线;r² - r·(2 + cosθ) + 1 = 0,一个同时有内外两支的闭合曲线;r³ - 3·r·cosθ + 2·sinθ = 0,极坐标和三角混合出来的怪异曲线。
这类方程你没法直接说"θ 等于多少,r 就等于多少"。固定某一个 θ,等式变成了关于 r 的一元方程,它可能有 0 个根、1 个根、2 个根,甚至更多。你想把曲线画出来,本质工作是:遍历感兴趣的 θ 区间,在每个 θ 上把对应的一个或多个 r 全部找出来,再统一转成直角坐标描点。
1.2 显式极坐标画法的局限
我最早图省事,遇到能解出 r = g(θ) 的形式就手动改写一下,用纯显式采样画。这个方法在 r = 1 + cosθ 上没问题,但一旦遇上 r² = a²·cos(2θ),开方之后会遇到 r = ±a·√cos(2θ) 两个分支。很多人在这里用力一挤,把两根并进一个 ± 符号,循环里画两遍,也能出来图形。
但这种处理有很强的侥幸心理:你预先知道根能显式解出来,才谈得上分支。换一个带一阶项的三次方程,比如 r³ - 3·r·cosθ + 2·sinθ = 0,没有任何标准函数能直接表达 r 关于 θ 的通式。到这一步,显式改写彻底哑火,你只能回到数值求根这条路上。
更阴险的一层是:有些方程形式上像显式,但改写成 f(θ,r) = r - g(θ) 之后,g(θ) 的计算本身不稳定。比如三角函数嵌套、分母接近零、根号内负数,这些在数值上都会把曲线撕裂成好几截。而统一走隐式求根,反而能在求根器内部把这些数值问题显式暴露出来,处理起来更可控。
1.3 一个 θ 方向有多个 r 解,直观想象一下
如果还没法直观理解"一个 θ 方向有多个 r",可以设想一个靶子:从原点向某个角度射出一条射线。显式方程是射线出去后,规定好这一段距离上刚好有一个点;隐式方程则让这条射线穿过曲线好几次,每次穿过的距离都不一样。
典型例子是方程 r² - r·(2 + cosθ) + 1 = 0,固定 θ=0 时变成 r² - 3r + 1 = 0,两个实根约等于 2.618 和 0.382。也就是说,沿 θ=0 方向从原点往右扫描,先后经过两个点。画这类图像如果只取其中一个根,结果只是半个轮廓,闭合曲线缺了一大块。
这也是 FuncPlotCalc 第一版和第二版的最大区别:第一版只用一个根,图像全是破洞;第二版实现多根采集后,曲线才真正闭合。所以整篇文章的基调很明确——所有设计都服务于同一个目标:在每一个 θ 方向上,把存在的根一个不落地找出来。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心破局点:把 f(θ,r)=0 变成一维求根问题
2.1 离散化策略:θ 采样与 r 搜索区间
极坐标隐式曲线归根结底是一条(或一组)平面曲线,而曲线可以看作"角度连续变化时极径取值的轨迹"。计算机画图必须离散化。我做的第一件事,就是把 θ 从 0 到 2π 切成一串等间距角度,步长记为 Δθ。
数值上,Δθ = 2π / N,N 通常取 720 到 3600。取太小(比如 N=180)图会明显多边形化,圆不圆、弧不弧;取太大则计算量翻倍,对求根的稳定性却帮助有限。就我实际经验,3600 已经足够细腻,换算成角度就是每 0.1° 采一个点,几千条短线段拼出来的曲线在屏幕上非常平滑。
r 的搜索区间同样要提前定好,这通常和坐标轴范围绑定。我的做法是提供一个 --rmax 参数,默认 5.0,求根只在一维区间 [-rmax, rmax] 内找。r 允许取负值非常重要——极坐标中很多隐式方程在不同象限的分支恰好落在 r 负半轴一侧,单纯找非负根会丢掉整片图形。
2.2 如何可靠地找根:符号变化 + 二分法
有了一维区间和目标函数 F(r) = f(θ0, r),找根就是个标准数值问题。我最先想到的是牛顿法,但后来放弃了:f 对 r 的偏导数在一些位置为零,初始点稍偏就发散,还容易越过奇点跳到完全错误的根。最终用的是更笨但更稳健的流程:
- 把
[-rmax, rmax]切成 M 个小区间(M 也是可调参数,默认 400); - 逐一检查每个小区间端点
F(a)和F(b); - 如果
F(a)·F(b) < 0,说明区间内至少穿过一个根,进入二分法; - 对落在小区间内的根,用二分法迭代 50 次,得到足够精确的解。
二分法最让人放心的地方在于:只要符号变化条件成立,它就一定收敛,不依赖初值,不会跳跃。速度慢一点,但在不追
