Created
May 2, 2023 05:18
-
-
Save chunibyo-wly/2d2d03356b351b0e84e5782e6973e292 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cairo | |
import numpy as np | |
import math | |
def cb(x1, y1, x4, y4, xc, yc): | |
ax = x1 - xc | |
ay = y1 - yc | |
bx = x4 - xc | |
by = y4 - yc | |
q1 = ax * ax + ay * ay | |
q2 = q1 + ax * bx + ay * by | |
k2 = (4 / 3) * ((2 * q1 * q2) ** 0.5 - q2) / (ax * by - ay * bx) | |
x2 = xc + ax - k2 * ay | |
y2 = yc + ay + k2 * ax | |
x3 = xc + bx + k2 * by | |
y3 = yc + by - k2 * bx | |
return x2, y2, x3, y3 | |
def bezier_circle_center(p0, p1, p2): | |
""" | |
计算二阶贝塞尔曲线的圆心坐标 | |
:param P0: 起点 | |
:param P1: 控制点 | |
:param P2: 终点 | |
:return: 圆心坐标 | |
""" | |
p0 = np.asarray(p0) | |
p1 = np.asarray(p1) | |
p2 = np.asarray(p2) | |
v1, v2 = p0 - p1, p2 - p1 | |
l1, l2 = np.linalg.norm(v1), np.linalg.norm(v2) | |
# assert is_close(l1, l2) and not is_close(l1, 0) | |
theta = np.arccos(np.dot(v1 / l1, v2 / l2)) | |
tan_half_theta = np.tan(theta / 2) | |
r = l1 * tan_half_theta | |
o2control_distance = np.sqrt(r**2 + l1**2) | |
control2target_distance = o2control_distance - r | |
control2target_dir = (v1 + v2) / np.linalg.norm(v1 + v2) | |
target_point = control2target_dir * control2target_distance + p1 | |
o = control2target_dir * o2control_distance + p1 | |
return (target_point, o) | |
# creating a SVG surface | |
# here geek95 is file name & 700, 700 is dimension | |
with cairo.SVGSurface("geek95.svg", 2000, 2000) as surface: | |
# creating a cairo context object for SVG surface | |
# using Context method | |
context = cairo.Context(surface) | |
x1, y1 = 0, 0 | |
control = np.asarray((500, 400)) | |
x4, y4 = control[0] * 2, 0 | |
# 二阶 | |
# https://blog.csdn.net/sl8023dxf/article/details/112624927 | |
context.move_to(x1, y1) | |
C1 = np.asarray([x1, y1]) | |
C4 = np.asarray([x4, y4]) | |
C2 = C1 + 2 / 3 * (control - C1) | |
C3 = C4 + 2 / 3 * (control - C4) | |
context.curve_to(C2[0], C2[1], C3[0], C3[1], x4, y4) | |
context.set_source_rgb(1, 0, 0) | |
context.set_line_width(10) | |
context.stroke() | |
# 三阶 | |
_, (xc, yc) = bezier_circle_center((x1, y1), (control[0], control[1]), (x4, y4)) | |
x2, y2, x3, y3 = cb(x1, y1, x4, y4, xc, yc) | |
context.move_to(x1, y1) | |
context.curve_to(x2, y2, x3, y3, x4, y4) | |
context.set_source_rgb(0, 1, 0) | |
context.set_line_width(10) | |
context.stroke() | |
# 圆弧 | |
# context.move_to(x1, y1) | |
# context.arc(control[0], 0, control[0], 0, 0.5 * math.pi) | |
radian = math.atan((y4 - yc) / (x4 - xc)) | |
context.arc( | |
xc, yc, ((xc - x1) ** 2 + (yc - y1) ** 2) ** 0.5, radian, math.pi - radian | |
) | |
context.set_source_rgb(0, 0, 1) | |
context.set_line_width(5) | |
context.stroke() |
Author
chunibyo-wly
commented
May 2, 2023
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment