我想用给定的次轴和长轴值计算椭圆的周长。我目前正在使用 Python 。
我计算了椭圆的短轴和长轴长度,即 a 和 b 。
计算面积很容易,但我想计算椭圆的周长来计算圆角长度。你有什么主意吗 ?
答案 0 :(得分:4)
定义问题:主轴,短轴与半主轴,半轴不同 OP应该是明确的,那些抓住,与在线解决方案相比应该是
您可以(以数字方式)解决问题,我使用完整的轴定义
from sympy import *
a, b, w = symbols('a b w')
x = a/2 * cos(w)
y = b/2 * sin(w)
dx = diff(x, w)
dy = diff(y, w)
ds = sqrt(dx**2 + dy**2)
def perimeter(majr, minr):
return Integral(ds.subs([(a,majr),(b,minr)]), (w, 0, 2*pi)).evalf().doit()
print('test1: a, b = 1 gives dia = 1 circle, perimeter/pi = ',
perimeter(1, 1)/pi.evalf())
print('test2: a, b = 4,6 ellipse perimeter = ', perimeter(4,6))
test1: a, b = 1 gives dia = 1 circle, perimeter/pi = 1.00000000000000
test2: a, b = 4,6 ellipse perimeter = 15.8654395892906
它也可以导出符号ds方程作为函数来尝试其他Python lib集成函数
func_dw = lambdify((w, a, b), ds)
from scipy import integrate
print(integrate.quad(func_dw, 0, 2*np.pi, args=(4, 6)))
(15.865439589290586, 2.23277254813499e-12)
scipy.integrate.quad(func,a,b,args =()...
返回:
y:float,从a到b的func的积分。
abserr:float,估计的 结果中的绝对错误
答案 1 :(得分:2)
根据Ramanujan的寻找椭圆周长的近似公式 - >
>>> import math
>>>
>>> def calculate_perimeter(a,b):
... perimeter = math.pi * ( 3*(a+b) - math.sqrt( (3*a + b) * (a + 3*b) ) )
... return perimeter
...
>>> calculate_perimeter(2,3)
15.865437575563961
您可以将结果与google calculator进行比较
答案 2 :(得分:2)
如Mark所说的in a comment,您可以简单地使用scipy.special.ellipe
。此实现使用complete elliptic integral of the second kind中近似的original C function ellpe.c
。如scipy的文档所述:
计算使用近似值
E(m)〜P(1-m)-(1-m)log(1-m)Q(1-m)
其中 P 和 Q 是十阶多项式
from scipy.special import ellipe
a = 3.5
b = 2.1
# eccentricity squared
e_sq = 1.0 - b**2/a**2
# circumference formula
C = 4 * a * ellipe(e_sq)
17.868899204378693
答案 3 :(得分:1)
这是一种比较上述答案的元答案。
实际上,Ramanujan 的二次近似比 Rezwan4029 的答案中的公式(使用 Ramanujan 的第一近似)更准确,也更复杂一些。第二个近似值是:
π * ((a+b) + (3(a-b)²) / (10*(a+b) + sqrt(a² + 14ab + b²)))
但我查看了上述所有答案并比较了他们的结果。出于稍后会变得显而易见的充分理由,我选择了 Gabriel 的版本作为真相来源,即与其他版本进行比较的价值。
对于 Rezwan4029 给出的答案,我在 2**(-10) .. 2**9
的网格上绘制了误差百分比。这是结果(两个轴都是幂,所以点 (3|5) 显示了半径为 2**3, 2**5
的椭圆的误差):
很明显,只有功率的差异与误差有关,所以我也画了这个:
无论如何,误差范围从圆的 0 到极偏心椭圆的 0.45%。根据您的应用,这可能是完全可以接受的,或者使解决方案无法使用。
对于拉马努金第二近似公式,情况非常相似,误差约为前者的 1/10:
Mark Dickinson 的 sympy 解决方案和 Gabriel 的 scipy 解决方案仍然有一些差异,但它们最多在 1e-6 的范围内,所以是一个不同的球场。但是sympy的解决方案非常慢,所以在大多数情况下可能应该使用scipy版本。
为了完整起见,这里是误差的分布(这次误差的对数在z轴上,否则它不会告诉我们太多,所以高度大致对应于有效位数):
结论:使用scipy方法。它很快,而且很可能非常准确,甚至可能是三种建议方法中最准确的。
答案 4 :(得分:0)
有一些很好的答案,但我想在精确/近似计算以及计算速度方面澄清一些事情。
对于精确的周长,请使用@Gabriel 所述的 scipy.special.ellipe。由于这是用 C 实现的,因此它也是最快的方法。
对于使用纯 python 的精确圆周,请查看我的 pyellipse 代码 https://gist.github.com/TimSC/4be20baeac7890e15773d31efb752d23 这段代码比使用 scipy.special.ellipe 慢大约 5 倍。使用的方法是 Gauss Kummer 用于低偏心率,Cayley 1876 用于高偏心率,如 http://www.numericana.com/answer/ellipse.htm#convergence
建议的对于计算速度快且没有 scipy 依赖性的良好近似,请参阅@Alfe 描述的 Ramanujan 的第二近似
对于另一个计算速度快(避免使用平方根)的好的近似值,请使用 Jacobsen 和 Waadeland 1985 年的 Padé 近似值 http://www.numericana.com/answer/ellipse.htm#hudson
h = pow(a-b, 2.0) / pow(a+b, 2.0)
C = (math.pi * (a+b) * (256.0 - 48.0 * h - 21.0 * h*h)
/(256.0 - 112.0 * h + 3.0 * h*h))
还有许多其他方法,但这些方法对于普通应用程序最有用。