gpt4 book ai didi

python - 在 Python 中实现 SVG 圆弧曲线

转载 作者:太空狗 更新时间:2023-10-29 21:03:40 26 4
gpt4 key购买 nike

我试图在 Python 中实现 SVG 路径计算,但我遇到了弧形曲线的问题。

我认为问题出在端点到中心参数化的转换上,但我找不到问题所在。您可以在 SVG specifications 的 F6.5 节中找到有关如何实现它的说明。 .我也看过其他语言的实现,但我也看不出它们有什么不同。

我的 Arc 对象实现在这里:

class Arc(object):

def __init__(self, start, radius, rotation, arc, sweep, end):
"""radius is complex, rotation is in degrees,
large and sweep are 1 or 0 (True/False also work)"""

self.start = start
self.radius = radius
self.rotation = rotation
self.arc = bool(arc)
self.sweep = bool(sweep)
self.end = end

self._parameterize()

def _parameterize(self):
# Conversion from endpoint to center parameterization
# http://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes

cosr = cos(radians(self.rotation))
sinr = sin(radians(self.rotation))
dx = (self.start.real - self.end.real) / 2
dy = (self.start.imag - self.end.imag) / 2
x1prim = cosr * dx + sinr * dy
x1prim_sq = x1prim * x1prim
y1prim = -sinr * dx + cosr * dy
y1prim_sq = y1prim * y1prim

rx = self.radius.real
rx_sq = rx * rx
ry = self.radius.imag
ry_sq = ry * ry

# Correct out of range radii
radius_check = (x1prim_sq / rx_sq) + (y1prim_sq / ry_sq)
if radius_check > 1:
rx *= sqrt(radius_check)
ry *= sqrt(radius_check)
rx_sq = rx * rx
ry_sq = ry * ry

t1 = rx_sq * y1prim_sq
t2 = ry_sq * x1prim_sq
c = sqrt((rx_sq * ry_sq - t1 - t2) / (t1 + t2))
if self.arc == self.sweep:
c = -c
cxprim = c * rx * y1prim / ry
cyprim = -c * ry * x1prim / rx

self.center = complex((cosr * cxprim - sinr * cyprim) +
((self.start.real + self.end.real) / 2),
(sinr * cxprim + cosr * cyprim) +
((self.start.imag + self.end.imag) / 2))

ux = (x1prim - cxprim) / rx
uy = (y1prim - cyprim) / ry
vx = (-x1prim - cxprim) / rx
vy = (-y1prim - cyprim) / ry
n = sqrt(ux * ux + uy * uy)
p = ux
theta = degrees(acos(p / n))
if uy > 0:
theta = -theta
self.theta = theta % 360

n = sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy))
p = ux * vx + uy * vy
if p == 0:
delta = degrees(acos(0))
else:
delta = degrees(acos(p / n))
if (ux * vy - uy * vx) < 0:
delta = -delta
self.delta = delta % 360
if not self.sweep:
self.delta -= 360

def point(self, pos):
if self.arc == self.sweep:
angle = radians(self.theta - (self.delta * pos))
else:
angle = radians(self.delta + (self.delta * pos))

x = sin(angle) * self.radius.real + self.center.real
y = cos(angle) * self.radius.imag + self.center.imag
return complex(x, y)

您可以使用以下将使用 Turtle 模块绘制曲线的代码对此进行测试。 (最后的raw_input()只是为了程序退出时屏幕不消失)。

arc1 = Arc(0j, 100+50j, 0, 0, 0, 100+50j)
arc2 = Arc(0j, 100+50j, 0, 1, 0, 100+50j)
arc3 = Arc(0j, 100+50j, 0, 0, 1, 100+50j)
arc4 = Arc(0j, 100+50j, 0, 1, 1, 100+50j)

import turtle
t = turtle.Turtle()
t.penup()
t.goto(0, 0)
t.dot(5, 'red')
t.write('Start')
t.goto(100, 50)
t.dot(5, 'red')
t.write('End')
t.pencolor = t.color('blue')

for arc in (arc1, arc2, arc3, arc4):
t.penup()
p = arc.point(0)
t.goto(p.real, p.imag)
t.pendown()
for x in range(1,101):
p = arc.point(x*0.01)
t.goto(p.real, p.imag)

raw_input()

问题:

绘制的这四个圆弧中的每一个都应该从起点绘制到终点。然而,它们是从错误的点得出的。两条曲线从末端到起点,两条曲线从 100,-50 到 0,0,而不是从 0,0 到 100, 50。

部分问题在于实现说明为您提供了从端点到中心的转换公式,但没有解释它在几何上的作用,所以我不清楚每个步骤的作用。对此的解释也会有所帮助。

最佳答案

我想我在您的代码中发现了一些错误:

theta = degrees(acos(p / n))
if uy > 0:
theta = -theta
self.theta = theta % 360

条件uy > 0错了,正确的是uy < 0 (如果 (1, 0) 则从 (ux, uy)uy < 0 的定向角为负):

theta = degrees(acos(p / n))
if uy < 0:
theta = -theta
self.theta = theta % 360

然后

if self.arc == self.sweep:
angle = radians(self.theta - (self.delta * pos))
else:
angle = radians(self.delta + (self.delta * pos))

这里不需要区分,sweeparc参数已在 theta 中说明和 delta .这可以简化为:

angle = radians(self.theta + (self.delta * pos))

最后

x = sin(angle) * self.radius.real + self.center.real
y = cos(angle) * self.radius.imag + self.center.imag

在这里sincos混淆了,正确的是

x = cos(angle) * self.radius.real + self.center.real
y = sin(angle) * self.radius.imag + self.center.imag

经过这些修改后,程序按预期运行。


编辑:还有一个问题。 point方法不考虑可能的 rotation范围。以下版本应该是正确的:

def point(self, pos):
angle = radians(self.theta + (self.delta * pos))
cosr = cos(radians(self.rotation))
sinr = sin(radians(self.rotation))

x = cosr * cos(angle) * self.radius.real - sinr * sin(angle) * self.radius.imag + self.center.real
y = sinr * cos(angle) * self.radius.real + cosr * sin(angle) * self.radius.imag + self.center.imag
return complex(x, y)

(参见 SVG specification 中的公式 F.6.3.1。)

关于python - 在 Python 中实现 SVG 圆弧曲线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14399406/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com