diff --git a/examples/canvas/bezier.py b/examples/canvas/bezier.py index c45eab42c..7138850c2 100644 --- a/examples/canvas/bezier.py +++ b/examples/canvas/bezier.py @@ -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__': diff --git a/kivy/graphics/vertex_instructions.pyx b/kivy/graphics/vertex_instructions.pyx index 4cfe20113..cc2f9038c 100644 --- a/kivy/graphics/vertex_instructions.pyx +++ b/kivy/graphics/vertex_instructions.pyx @@ -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 = malloc(self._segments * sizeof(vertex_t)) + vertices = malloc((self._segments + 1) * sizeof(vertex_t)) if vertices == NULL: raise MemoryError('vertices') - indices = malloc(self._segments * sizeof(unsigned short)) + indices = 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)