mirror of https://github.com/kivy/kivy.git
work on bezier curve
optimised bezier algorithm (no more nested lists, use less ram) fixed last point problem (curves wasn't goint up to it) added loop option to bezier curve updated example widget
This commit is contained in:
parent
1ace31dfdf
commit
5497370493
|
@ -5,23 +5,11 @@ from kivy.uix.widget import Widget
|
||||||
from kivy.graphics import Color, Line, Bezier, Ellipse, Line
|
from kivy.graphics import Color, Line, Bezier, Ellipse, Line
|
||||||
|
|
||||||
class BezierTest(Widget):
|
class BezierTest(Widget):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, points=[], loop=False, *args, **kwargs):
|
||||||
super(BezierTest, self).__init__(*args, **kwargs)
|
super(BezierTest, self).__init__(*args, **kwargs)
|
||||||
self.d = 10
|
self.d = 10
|
||||||
self.points = [
|
self.points = points
|
||||||
0, 0,
|
self.loop = loop
|
||||||
0.1 * self.width, 0.2 * self.height,
|
|
||||||
0.2 * self.width, 0.3 * self.height,
|
|
||||||
0.3 * self.width, 0.3 * self.height,
|
|
||||||
0.4 * self.width, 0.4 * self.height,
|
|
||||||
0.5 * self.width, 0.5 * self.height,
|
|
||||||
0.6 * self.width, 0.6 * self.height,
|
|
||||||
0.7 * self.width, 0.6 * self.height,
|
|
||||||
0.8 * self.width, 0.7 * self.height,
|
|
||||||
0.9 * self.width, 0.8 * self.height,
|
|
||||||
self.width, self.height,
|
|
||||||
0, self.height]
|
|
||||||
|
|
||||||
self.current_point = None
|
self.current_point = None
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
@ -30,7 +18,7 @@ class BezierTest(Widget):
|
||||||
with self.canvas:
|
with self.canvas:
|
||||||
Color(1.0, 0.0, 0.0)
|
Color(1.0, 0.0, 0.0)
|
||||||
|
|
||||||
Bezier(points=self.points, segments=100)
|
Bezier(points=self.points, segments=150, loop=self.loop)
|
||||||
|
|
||||||
Color(1.0, 1.0, 1.0)
|
Color(1.0, 1.0, 1.0)
|
||||||
for p in zip(self.points[::2], self.points[1::2]):
|
for p in zip(self.points[::2], self.points[1::2]):
|
||||||
|
@ -39,27 +27,25 @@ class BezierTest(Widget):
|
||||||
size=(self.d, self.d))
|
size=(self.d, self.d))
|
||||||
|
|
||||||
Color(1.0, 0.0, 1.0)
|
Color(1.0, 0.0, 1.0)
|
||||||
Line(points=self.points)
|
Line(points=self.points+self.points[:2])
|
||||||
|
|
||||||
|
|
||||||
def on_touch_down(self, touch):
|
def on_touch_down(self, touch):
|
||||||
if self.collide_point(touch.pos[0], touch.pos[1]):
|
if self.collide_point(touch.pos[0], touch.pos[1]):
|
||||||
|
|
||||||
|
|
||||||
for i, p in enumerate(zip(self.points[::2], self.points[1::2])):
|
for i, p in enumerate(zip(self.points[::2], self.points[1::2])):
|
||||||
if (
|
if (
|
||||||
abs(touch.pos[0] - self.pos[0] - p[0]) < self.d and
|
abs(touch.pos[0] - self.pos[0] - p[0]) < self.d and
|
||||||
abs(touch.pos[1] - self.pos[1] - p[1]) < self.d):
|
abs(touch.pos[1] - self.pos[1] - p[1]) < self.d):
|
||||||
self.current_point = i + 1
|
self.current_point = i + 1
|
||||||
return True
|
return True
|
||||||
super(BezierTest, self).on_touch_down(touch)
|
return super(BezierTest, self).on_touch_down(touch)
|
||||||
|
|
||||||
def on_touch_up(self, touch):
|
def on_touch_up(self, touch):
|
||||||
if self.collide_point(touch.pos[0], touch.pos[1]):
|
if self.collide_point(touch.pos[0], touch.pos[1]):
|
||||||
if self.current_point:
|
if self.current_point:
|
||||||
self.current_point = None
|
self.current_point = None
|
||||||
return True
|
return True
|
||||||
super(BezierTest, self).on_touch_up(touch)
|
return super(BezierTest, self).on_touch_up(touch)
|
||||||
|
|
||||||
def on_touch_move(self, touch):
|
def on_touch_move(self, touch):
|
||||||
if self.collide_point(touch.pos[0], touch.pos[1]):
|
if self.collide_point(touch.pos[0], touch.pos[1]):
|
||||||
|
@ -68,13 +54,26 @@ class BezierTest(Widget):
|
||||||
self.points[(self.current_point - 1) * 2 + 1] = touch.pos[1] - self.pos[1]
|
self.points[(self.current_point - 1) * 2 + 1] = touch.pos[1] - self.pos[1]
|
||||||
self.update()
|
self.update()
|
||||||
return True
|
return True
|
||||||
super(BezierTest, self).on_touch_move(touch)
|
return super(BezierTest, self).on_touch_move(touch)
|
||||||
|
|
||||||
|
|
||||||
class Main(App):
|
class Main(App):
|
||||||
def build(self):
|
def build(self):
|
||||||
layout = FloatLayout()
|
layout = FloatLayout()
|
||||||
layout.add_widget(BezierTest())
|
layout.add_widget(BezierTest(points=[
|
||||||
|
0, 0,
|
||||||
|
0.1 * 100, 0.2 * 100,
|
||||||
|
0.2 * 100, 0.3 * 100,
|
||||||
|
0.3 * 100, 0.3 * 100,
|
||||||
|
0.4 * 100, 0.4 * 100,
|
||||||
|
0.5 * 100, 0.5 * 100,
|
||||||
|
0.6 * 100, 0.6 * 100,
|
||||||
|
0.7 * 100, 0.6 * 100,
|
||||||
|
0.8 * 100, 0.7 * 100,
|
||||||
|
0.9 * 100, 0.8 * 100,
|
||||||
|
100, 100,
|
||||||
|
0, 100], loop=True))
|
||||||
|
|
||||||
return layout
|
return layout
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -89,28 +89,42 @@ cdef class Bezier(VertexInstruction):
|
||||||
`segments`: int, default to 180
|
`segments`: int, default to 180
|
||||||
Define how much segment is needed for drawing the ellipse.
|
Define how much segment is needed for drawing the ellipse.
|
||||||
The drawing will be smoother if you have lot of segment.
|
The drawing will be smoother if you have lot of segment.
|
||||||
|
`loop`: bool, default to False
|
||||||
|
Set the bezier curve to join last point to first.
|
||||||
|
|
||||||
|
#TODO: refactoring:
|
||||||
|
a) find interface common to all splines (given control points and
|
||||||
|
perhaps tangents, what's the position on the spline for parameter t),
|
||||||
|
|
||||||
|
b) make that a superclass Spline, c) create BezierSpline subclass that
|
||||||
|
does the computation
|
||||||
'''
|
'''
|
||||||
cdef list _points
|
cdef list _points
|
||||||
cdef int _segments
|
cdef int _segments
|
||||||
|
cdef bint _loop
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
VertexInstruction.__init__(self, **kwargs)
|
VertexInstruction.__init__(self, **kwargs)
|
||||||
self.points = kwargs.get('points', [])
|
self.points = kwargs.get('points', [])
|
||||||
self._segments = kwargs.get('segments', 10)
|
self._segments = kwargs.get('segments', 10)
|
||||||
|
self._loop = kwargs.get('loop', False)
|
||||||
|
if self._loop:
|
||||||
|
self.points.extend(self.points[:2])
|
||||||
self.batch.set_mode('line_strip')
|
self.batch.set_mode('line_strip')
|
||||||
|
|
||||||
cdef void build(self):
|
cdef void build(self):
|
||||||
cdef int x, i, j
|
cdef int x, i, j
|
||||||
cdef float l
|
cdef float l
|
||||||
cdef list T
|
cdef list T = self.points
|
||||||
cdef vertex_t *vertices = NULL
|
cdef vertex_t *vertices = NULL
|
||||||
cdef unsigned short *indices = NULL
|
cdef unsigned short *indices = NULL
|
||||||
|
|
||||||
vertices = <vertex_t *>malloc(self._segments * sizeof(vertex_t))
|
vertices = <vertex_t *>malloc((self._segments + 1) * sizeof(vertex_t))
|
||||||
if vertices == NULL:
|
if vertices == NULL:
|
||||||
raise MemoryError('vertices')
|
raise MemoryError('vertices')
|
||||||
|
|
||||||
indices = <unsigned short *>malloc(self._segments * sizeof(unsigned short))
|
indices = <unsigned short *>malloc(
|
||||||
|
(self._segments + 1) * sizeof(unsigned short))
|
||||||
if indices == NULL:
|
if indices == NULL:
|
||||||
free(vertices)
|
free(vertices)
|
||||||
raise MemoryError('indices')
|
raise MemoryError('indices')
|
||||||
|
@ -118,19 +132,20 @@ cdef class Bezier(VertexInstruction):
|
||||||
for x in xrange(self._segments):
|
for x in xrange(self._segments):
|
||||||
l = x / (1.0 * self._segments)
|
l = x / (1.0 * self._segments)
|
||||||
|
|
||||||
T = [zip(self.points[::2], self.points[1::2]),]
|
for i in range(1, len(self.points)):
|
||||||
for i in range(1, len(self.points)/2):
|
for j in xrange(len(self.points) - 2*i):
|
||||||
T.append([])
|
T[j] = T[j] + (T[j+2] - T[j]) * l
|
||||||
for j in xrange(len(self.points)/2 - i):
|
|
||||||
T[i].append([
|
|
||||||
T[i-1][j][0] + (T[i-1][j+1][0] - T[i-1][j][0]) * l,
|
|
||||||
T[i-1][j][1] + (T[i-1][j+1][1] - T[i-1][j][1]) * l])
|
|
||||||
|
|
||||||
vertices[x].x = T[-1][0][0]
|
vertices[x].x = T[0]
|
||||||
vertices[x].y = T[-1][0][1]
|
vertices[x].y = T[1]
|
||||||
indices[x] = x
|
indices[x] = x
|
||||||
|
|
||||||
self.batch.set_data(vertices, self._segments, indices, self._segments)
|
vertices[x+1].x = self.points[-2]
|
||||||
|
vertices[x+1].y = self.points[-1]
|
||||||
|
indices[x+1] = x + 1
|
||||||
|
|
||||||
|
self.batch.set_data(vertices, self._segments + 1, indices,
|
||||||
|
self._segments + 1)
|
||||||
|
|
||||||
free(vertices)
|
free(vertices)
|
||||||
free(indices)
|
free(indices)
|
||||||
|
|
Loading…
Reference in New Issue