To pytanie jest pierwszym wynikiem wyszukiwania w Google „ścieżki zaokrąglonych rogów svg”. Sugestia Phrogz do użyciastroke
ma pewne ograniczenia (mianowicie, że nie mogę używać obrysu do innych celów i że wymiary muszą być skorygowane o szerokość obrysu).
Sugestia Jlange, aby użyć krzywej, jest lepsza, ale niezbyt konkretna. Skończyło się na użyciu kwadratowych krzywych Béziera do rysowania zaokrąglonych rogów. Rozważ to zdjęcie narożnika oznaczonego niebieską kropką i dwoma czerwonymi punktami na sąsiednich krawędziach:
Dwie linie można utworzyć za pomocą L
polecenia. Aby zmienić ten ostry narożnik w zaokrąglony, zacznij rysować krzywą od lewego czerwonego punktu (użyj, M x,y
aby przejść do tego punktu). Teraz kwadratowa krzywa Béziera ma tylko jeden punkt kontrolny, który należy ustawić na niebieskim punkcie. Ustaw koniec krzywej w prawym czerwonym punkcie. Ponieważ styczna w dwóch czerwonych punktach jest skierowana w kierunku poprzednich linii, zobaczysz płynne przejście, „zaokrąglone rogi”.
Teraz, aby kontynuować kształt za zaokrąglonym rogiem, można uzyskać prostą linię na krzywej Béziera, ustawiając punkt kontrolny między na linii między dwoma rogami.
Aby pomóc mi w określeniu ścieżki, napisałem ten skrypt w Pythonie, który akceptuje krawędzie i promień. Matematyka wektorowa sprawia, że jest to naprawdę bardzo łatwe. Wynikowy obraz z wyjścia:
#!/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
i jego warianty nie działają w SVG.