Câu hỏi này là kết quả đầu tiên cho "đường dẫn các góc tròn svg" của Google. Đề xuất sử dụng của Phrogz stroke
có một số hạn chế (cụ thể là tôi không thể sử dụng nét vẽ cho các mục đích khác và kích thước phải được hiệu chỉnh cho chiều rộng nét vẽ).
Jlange gợi ý sử dụng một đường cong là tốt hơn, nhưng không cụ thể lắm. Cuối cùng tôi đã sử dụng các đường cong Bézier bậc hai để vẽ các góc tròn. Hãy xem xét hình ảnh này về một góc được đánh dấu bằng một chấm màu xanh lam và hai điểm màu đỏ trên các cạnh liền kề:
Hai dòng có thể được thực hiện bằng L
lệnh. Để biến góc nhọn này thành góc tròn, hãy bắt đầu vẽ một đường cong từ điểm màu đỏ bên trái (dùng M x,y
để di chuyển đến điểm đó). Bây giờ, một đường cong Bézier bậc hai chỉ có một điểm điều khiển duy nhất mà bạn phải đặt trên điểm màu xanh lam. Đặt phần cuối của đường cong tại điểm màu đỏ bên phải. Khi tiếp tuyến tại hai điểm màu đỏ theo hướng của các đường trước đó, bạn sẽ thấy sự chuyển đổi trôi chảy, "các góc tròn".
Bây giờ để tiếp tục hình dạng sau khi góc tròn, một đường thẳng trong đường cong Bézier có thể đạt được bằng cách thiết lập điểm điều khiển giữa trên đường giữa hai góc.
Để giúp tôi xác định đường dẫn, tôi đã viết tập lệnh Python này chấp nhận các cạnh và bán kính. Toán học vectơ làm cho điều này thực sự rất dễ dàng. Hình ảnh kết quả từ đầu ra:
#!/usr/bin/env python
# Given some vectors and a border-radius, output a SVG path with rounded
# corners.
#
# Copyright (C) Peter Wu <peter@lekensteyn.nl>
from math import sqrt
class Vector(object):
def __init__(self, x, y):
self.x = x
self.y = y
def sub(self, vec):
return Vector(self.x - vec.x, self.y - vec.y)
def add(self, vec):
return Vector(self.x + vec.x, self.y + vec.y)
def scale(self, n):
return Vector(self.x * n, self.y * n)
def length(self):
return sqrt(self.x**2 + self.y**2)
def normal(self):
length = self.length()
return Vector(self.x / length, self.y / length)
def __str__(self):
x = round(self.x, 2)
y = round(self.y, 2)
return '{},{}'.format(x, y)
# A line from vec_from to vec_to
def line(vec_from, vec_to):
half_vec = vec_from.add(vec_to.sub(vec_from).scale(.5))
return '{} {}'.format(half_vec, vec_to)
# Adds 'n' units to vec_from pointing in direction vec_to
def vecDir(vec_from, vec_to, n):
return vec_from.add(vec_to.sub(vec_from).normal().scale(n))
# Draws a line, but skips 'r' units from the begin and end
def lineR(vec_from, vec_to, r):
vec = vec_to.sub(vec_from).normal().scale(r)
return line(vec_from.add(vec), vec_to.sub(vec))
# An edge in vec_from, to vec_to with radius r
def edge(vec_from, vec_to, r):
v = vecDir(vec_from, vec_to, r)
return '{} {}'.format(vec_from, v)
# Hard-coded border-radius and vectors
r = 5
a = Vector( 0, 60)
b = Vector(100, 0)
c = Vector(100, 200)
d = Vector( 0, 200 - 60)
path = []
# Start below top-left edge
path.append('M {} Q'.format(a.add(Vector(0, r))))
# top-left edge...
path.append(edge(a, b, r))
path.append(lineR(a, b, r))
path.append(edge(b, c, r))
path.append(lineR(b, c, r))
path.append(edge(c, d, r))
path.append(lineR(c, d, r))
path.append(edge(d, a, r))
path.append(lineR(d, a, r))
# Show results that can be pushed into a <path d="..." />
for part in path:
print(part)
border-radius
và các biến thể của nó không hoạt động trong SVG.