Skip to content

Instantly share code, notes, and snippets.

@lw
Created September 6, 2018 09:41
Show Gist options
  • Save lw/52dfe9759102fa090d46e09d8c2db5de to your computer and use it in GitHub Desktop.
Save lw/52dfe9759102fa090d46e09d8c2db5de to your computer and use it in GitHub Desktop.
Utils from my M1 internship to draw Bezier curves in LaTeX. Find the coordinate of a point along a curve given by its TikZ parameters, split a curve in two at a given point, find the best curve for an arc.
import math
fixed = 0.552284749831 / math.sqrt(2)
fixed = 0.3915
print(fixed)
def get_point_along_bezier(p1, p2, r, out_d, in_d, rel, out_l, in_l, t):
dx = p2[0] - p1[0]
dy = p2[1] - p1[1]
angle = math.atan2(dy, dx)
out_angle = out_d / 360 * 2 * math.pi + (angle if rel else 0)
print("out angle = %g" % (out_angle / 2 / math.pi * 360))
in_angle = in_d / 360 * 2 * math.pi + (angle if rel else 0)
print("in angle = %g" % (in_angle / 2 / math.pi * 360))
p1_ = (p1[0] + r * math.cos(out_angle),
p1[1] + r * math.sin(out_angle))
p2_ = (p2[0] + r * math.cos(in_angle),
p2[1] + r * math.sin(in_angle))
dx_ = p2_[0] - p1_[0]
dy_ = p2_[1] - p1_[1]
dist = math.hypot(dx_, dy_) - 2 * r
c1 = (p1[0] + math.cos(out_angle) * dist * fixed * out_l,
p1[1] + math.sin(out_angle) * dist * fixed * out_l)
c2 = (p2[0] + math.cos(in_angle) * dist * fixed * in_l,
p2[1] + math.sin(in_angle) * dist * fixed * in_l)
print(c1)
print(c2)
res = ((1-t) ** 3 * p1_[0] + 3 * t * (1-t) ** 2 * c1[0] + 3 * t ** 2 * (1-t) * c2[0] + t ** 3 * p2_[0],
(1-t) ** 3 * p1_[1] + 3 * t * (1-t) ** 2 * c1[1] + 3 * t ** 2 * (1-t) * c2[1] + t ** 3 * p2_[1])
print("\draw (%g,%g) .. controls (%g,%g) and (%g,%g) .. (%g,%g);" % (*p1, *c1, *c2, *p2))
print(res)
#if __name__ == "__main__":
# p1 = (0,1)
# p2 = (0.5878,-0.809)
# get_point_along_bezier(p1, p2, 0.070292, 120, 72, True, 2.5, 2.5, 0.5)
def split_bezier(p1, c1, c2, p2, t):
mid = ((1-t) ** 3 * p1[0] + 3 * t * (1-t) ** 2 * c1[0] + 3 * t ** 2 * (1-t) * c2[0] + t ** 3 * p2[0],
(1-t) ** 3 * p1[1] + 3 * t * (1-t) ** 2 * c1[1] + 3 * t ** 2 * (1-t) * c2[1] + t ** 3 * p2[1])
cb1 = ((1-t) * p1[0] + t * c1[0],
(1-t) * p1[1] + t * c1[1])
cb2 = ((1-t) ** 2 * p1[0] + 2 * t * (1-t) * c1[0] + t ** 2 * c2[0],
(1-t) ** 2 * p1[1] + 2 * t * (1-t) * c1[1] + t ** 2 * c2[1])
ca1 = ((1-t) ** 2 * c1[0] + 2 * t * (1-t) * c2[0] + t ** 2 * p2[0],
(1-t) ** 2 * c1[1] + 2 * t * (1-t) * c2[1] + t ** 2 * p2[1])
ca2 = ((1-t) * c2[0] + t * p2[0],
(1-t) * c2[1] + t * p2[1])
print("\\node[vertex] at (%gcm,%gcm) {};\n\\draw (%gcm,%gcm) .. controls (%gcm,%gcm) and (%gcm,%gcm) .. (%gcm,%gcm);\n\\draw (%gcm,%gcm) .. controls (%gcm,%gcm) and (%gcm,%gcm) .. (%gcm,%gcm);" % (*mid, *p1, *cb1, *cb2, *mid, *mid, *ca1, *ca2, *p2))
print("split_bezier((%g,%g), (%g,%g), (%g,%g), (%g,%g), 0.5)" % (*p1, *cb1, *cb2, *mid))
print("split_bezier((%g,%g), (%g,%g), (%g,%g), (%g,%g), 0.5)" % (*mid, *ca1, *ca2, *p2))
if __name__ == "__main__":
split_bezier((0.5175063087380415/10, 10.57476996829815/10),
(13.327115975341446/10, 24.896916274786836/10),
(25.866100110358985/10, -8.026096033402922/10),
(6.651237496748978/10, -8.090097214314332/10), 0.42)
def make_bezier_for_arc(r, angle0, angle3):
angle1 = 2 * angle0 / 3 + angle3 / 3
angle2 = angle0 / 3 + 2 * angle3 / 3
p0 = (r * math.cos(angle0), r * math.sin(angle0))
p1 = (r * math.cos(angle1), r * math.sin(angle1))
p2 = (r * math.cos(angle2), r * math.sin(angle2))
p3 = (r * math.cos(angle3), r * math.sin(angle3))
a = numpy.empty((4,4))
xb = numpy.empty(4)
yb = numpy.empty(4)
for i in range(4):
p = locals()["p%d" % i]
t = i * 1 / 3
for j in range(4):
a[i,j] = [1,3,3,1][j] * (1-t) ** (3 - j) * t ** j
xb[i] = p[0]
yb[i] = p[1]
xs = numpy.linalg.solve(a, xb)
ys = numpy.linalg.solve(a, yb)
c1 = (xs[1], ys[1])
c2 = (xs[2], ys[2])
print("\\draw (%gcm,%gcm) .. controls (%gcm,%gcm) and (%gcm,%gcm) .. (%gcm,%gcm);" % (*p0, *c1, *c2, *p3))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment