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
|
||||
|
||||
class BezierTest(Widget):
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, points=[], loop=False, *args, **kwargs):
|
||||
super(BezierTest, self).__init__(*args, **kwargs)
|
||||
self.d = 10
|
||||
self.points = [
|
||||
0, 0,
|
||||
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.points = points
|
||||
self.loop = loop
|
||||
self.current_point = None
|
||||
self.update()
|
||||
|
||||
|
@ -30,7 +18,7 @@ class BezierTest(Widget):
|
|||
with self.canvas:
|
||||
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)
|
||||
for p in zip(self.points[::2], self.points[1::2]):
|
||||
|
@ -39,27 +27,25 @@ class BezierTest(Widget):
|
|||
size=(self.d, self.d))
|
||||
|
||||
Color(1.0, 0.0, 1.0)
|
||||
Line(points=self.points)
|
||||
Line(points=self.points+self.points[:2])
|
||||
|
||||
|
||||
def on_touch_down(self, touch):
|
||||
if self.collide_point(touch.pos[0], touch.pos[1]):
|
||||
|
||||
|
||||
for i, p in enumerate(zip(self.points[::2], self.points[1::2])):
|
||||
if (
|
||||
abs(touch.pos[0] - self.pos[0] - p[0]) < self.d and
|
||||
abs(touch.pos[1] - self.pos[1] - p[1]) < self.d):
|
||||
self.current_point = i + 1
|
||||
return True
|
||||
super(BezierTest, self).on_touch_down(touch)
|
||||
return super(BezierTest, self).on_touch_down(touch)
|
||||
|
||||
def on_touch_up(self, touch):
|
||||
if self.collide_point(touch.pos[0], touch.pos[1]):
|
||||
if self.current_point:
|
||||
self.current_point = None
|
||||
return True
|
||||
super(BezierTest, self).on_touch_up(touch)
|
||||
return super(BezierTest, self).on_touch_up(touch)
|
||||
|
||||
def on_touch_move(self, touch):
|
||||
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.update()
|
||||
return True
|
||||
super(BezierTest, self).on_touch_move(touch)
|
||||
return super(BezierTest, self).on_touch_move(touch)
|
||||
|
||||
|
||||
class Main(App):
|
||||
def build(self):
|
||||
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
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -89,28 +89,42 @@ cdef class Bezier(VertexInstruction):
|
|||
`segments`: int, default to 180
|
||||
Define how much segment is needed for drawing the ellipse.
|
||||
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 int _segments
|
||||
cdef bint _loop
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
VertexInstruction.__init__(self, **kwargs)
|
||||
self.points = kwargs.get('points', [])
|
||||
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')
|
||||
|
||||
cdef void build(self):
|
||||
cdef int x, i, j
|
||||
cdef float l
|
||||
cdef list T
|
||||
cdef list T = self.points
|
||||
cdef vertex_t *vertices = 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:
|
||||
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:
|
||||
free(vertices)
|
||||
raise MemoryError('indices')
|
||||
|
@ -118,19 +132,20 @@ cdef class Bezier(VertexInstruction):
|
|||
for x in xrange(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)/2):
|
||||
T.append([])
|
||||
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])
|
||||
for i in range(1, len(self.points)):
|
||||
for j in xrange(len(self.points) - 2*i):
|
||||
T[j] = T[j] + (T[j+2] - T[j]) * l
|
||||
|
||||
vertices[x].x = T[-1][0][0]
|
||||
vertices[x].y = T[-1][0][1]
|
||||
vertices[x].x = T[0]
|
||||
vertices[x].y = T[1]
|
||||
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(indices)
|
||||
|
|
Loading…
Reference in New Issue