Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- def get_filled_path(points):
- from OpenGL.GLU import gluNewTess, gluTessNormal, gluTessProperty,\
- gluTessBeginPolygon, gluTessBeginContour, gluTessEndContour,\
- gluTessEndPolygon, gluTessCallback, gluErrorString, gluTessVertex,\
- GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO, GLU_TESS_VERTEX,\
- GLU_TESS_BEGIN, GLU_TESS_END, GLU_TESS_ERROR, GLU_TESS_COMBINE
- tess = gluNewTess()
- gluTessNormal(tess, 0, 0, 1)
- gluTessProperty(tess, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO)
- tess_list = []
- tess_style = None
- tess_shape = None
- def tess_vertex(vertex):
- global tess_shape
- tess_shape += list(vertex[0:2])
- def tess_begin(which):
- global tess_style, tess_shape
- tess_style = which
- tess_shape = []
- def tess_end():
- global tess_style, tess_shape
- tess_list.append((tess_style, tess_shape))
- def tess_error(code):
- err = gluErrorString(code)
- pymt.pymt_logger.warning('BezierPath: GLU Tesselation Error: %s' % str(err))
- gluTessCallback(tess, GLU_TESS_VERTEX, tess_vertex)
- gluTessCallback(tess, GLU_TESS_BEGIN, tess_begin)
- gluTessCallback(tess, GLU_TESS_END, tess_end)
- gluTessCallback(tess, GLU_TESS_ERROR, tess_error)
- gluTessBeginPolygon(tess, None)
- gluTessBeginContour(tess)
- for x, y in zip(points[::2], points[1::2]):
- v_data = (x, y, 0)
- gluTessVertex(tess, v_data, v_data)
- gluTessEndContour(tess)
- gluTessEndPolygon(tess)
- return tess_list
- def draw_filled_path(points):
- from OpenGL.GL import glVertex2f
- for style, points in points:
- with gx_begin(style):
- for x, y in zip(points[::2], points[1::2]):
- glVertex2f(x, y)
- def point_inside_polygon(x, y, poly):
- n = len(poly)
- if n < 2:
- return False
- inside = False
- p1x, p1y = poly[0]
- for i in range(n+1):
- p2x,p2y = poly[i % n]
- if y > min(p1y,p2y):
- if y <= max(p1y,p2y):
- if x <= max(p1x,p2x):
- if p1y != p2y:
- xinters = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
- if p1x == p2x or x <= xinters:
- inside = not inside
- p1x,p1y = p2x,p2y
- return inside
- class Curve(object):
- def __init__(self, points=[], tension=0., precision=1., is_closed=False):
- self._points = points
- self._tension = tension
- self._is_closed = is_closed
- self._curve = []
- self._filledpath = None
- self._precision = precision
- self.update()
- def update(self):
- p = self._points
- self._curve = []
- self._filledpath = None
- if len(self._points) < 2:
- return
- if len(self._points) == 2:
- p0, p1 = p
- self._curve = [p0[0], p0[1], p1[0], p1[1]]
- return
- n = len(p) - 1
- if self._is_closed:
- for i in xrange(n):
- if i == 0:
- o = self._curve_seg(p[n], p[0], p[1], p[2])
- elif i == (n - 1):
- o = self._curve_seg(p[n-2], p[n-1], p[n], p[0])
- else:
- o = self._curve_seg(p[i-1], p[i], p[i+1], p[i+2])
- self._curve += o
- self._curve += self._curve_seg(p[n-1], p[n], p[0], p[1])
- else:
- for i in xrange(n):
- if i == 0:
- o = self._curve_seg(p[0], p[0], p[1], p[2])
- elif i == (n - 1):
- o = self._curve_seg(p[n-2], p[n-1], p[n], p[n])
- else:
- o = self._curve_seg(p[i-1], p[i], p[i+1], p[i+2])
- self._curve += o
- def _curve_seg(self, p0, p1, p2, p3):
- curve = []
- p = self._precision
- tension = self._tension
- x = 0.
- y = 0.
- xl = p1[0] - 1.
- yl = p1[1] - 1.
- t = 0.
- f = 1.
- k = 1.1
- m1x = (1 - tension) * (p2[0] - p0[0]) / 2.
- m2x = (1 - tension) * (p3[0] - p1[0]) / 2.
- m1y = (1 - tension) * (p2[1] - p0[1]) / 2.
- m2y = (1 - tension) * (p3[1] - p1[1]) / 2.
- while t <= 1:
- x = (2 * t * t * t - 3 * t * t + 1) * p1[0] + \
- (t * t * t - 2 * t * t + t) * m1x + \
- (-2 * t * t * t + 3 * t * t) * p2[0] + \
- (t * t * t - t * t) * m2x
- y = (2 * t * t * t - 3 * t * t + 1) * p1[1] + \
- (t * t * t - 2 * t * t + t) * m1y + \
- (-2 * t * t * t + 3 * t * t) * p2[1] + \
- (t * t * t - t * t) * m2y
- #x = round(x)
- #y = round(y)
- if x != xl or y != yl:
- if x - xl > p or y - yl > p or xl - x > p or yl - y > p:
- t -= f
- f = f / k
- else:
- curve += [x, y]
- xl = x
- yl = y
- if t + f > 1.:
- t = 1 - f
- else:
- f = f * k
- t += f
- return curve
- @property
- def curve(self):
- return self._curve
- @property
- def filledpath(self):
- if self._filledpath is None:
- self._filledpath = get_filled_path(self.curve)
- return self._filledpath
- def _set_tension(self, value):
- if self._tension == value:
- return
- self._tension = value
- self.update()
- def _get_tension(self):
- return self._tension
- tension = property(_get_tension, _set_tension)
- def _set_points(self, value):
- if self._points == value:
- return
- self._points = value
- self.update()
- def _get_points(self):
- return self._points
- points = property(_get_points, _set_points)
- def _set_precision(self, value):
- if self._precision == value:
- return
- self._precision = value
- self.update()
- def _get_precision(self):
- return self._precision
- precision = property(_get_precision, _set_precision)
- def _set_is_closed(self, value):
- if self._is_closed == value:
- return
- self._is_closed = value
- self.update()
- def _get_is_closed(self):
- return self._is_closed
- is_closed = property(_get_is_closed, _set_is_closed)
- if __name__ == '__main__':
- from pymt import *
- w = getWindow()
- class Shape(MTWidget):
- def __init__(self, **kwargs):
- super(Shape, self).__init__(**kwargs)
- self.curve = Curve(precision=10)
- def r():
- import random
- if random.random() > .5:
- return .5
- return .3
- self.color = map(lambda x: r(), xrange(3)) + [.5]
- self.linecolor = self.color[:3] + [.7]
- self.circlecolor = map(lambda x: x + .1, self.color[:3])
- def collide_point(self, x, y):
- return point_inside_polygon(x, y, self.curve.points)
- def draw(self):
- c = self.curve
- if c.is_closed:
- set_color(*self.color)
- draw_filled_path(c.filledpath)
- set_color(*self.linecolor)
- drawLine(c.curve, width=5.)
- set_color(*self.circlecolor)
- for p in c.points:
- drawCircle(pos=p, radius=3)
- def on_touch_down(self, touch):
- if not self.collide_point(*touch.pos):
- return
- touch.grab(self)
- touch.userdata['controlpoints'] = []
- for idx in xrange(len(self.curve.points)):
- x, y = self.curve.points[idx]
- if Vector(x, y).distance(touch.pos) < 150:
- touch.userdata['controlpoints'].append(idx)
- return True
- def on_touch_move(self, touch):
- if touch.grab_current != self:
- return
- if touch.dpos == (0, 0):
- return
- p = self.curve.points
- for idx in touch.userdata['controlpoints']:
- d = Vector(touch.pos) - Vector(touch.dpos)
- p[idx] = Vector(p[idx]) + d
- self.curve.update()
- return True
- class Canvas(MTWidget):
- def __init__(self, **kwargs):
- super(Canvas, self).__init__(**kwargs)
- def on_touch_down(self, touch):
- if super(Canvas, self).on_touch_down(touch):
- return True
- shape = Shape()
- self.add_widget(shape)
- touch.userdata['shape'] = shape
- shape.curve.points = shape.curve.points + [touch.pos]
- shape.curve.points = shape.curve.points + [touch.pos]
- return True
- def on_touch_move(self, touch):
- if 'shape' in touch.userdata:
- shape = touch.userdata['shape']
- last = shape.curve.points[-2]
- if Vector(touch.pos).distance(Vector(last)) > 80:
- shape.curve.points = shape.curve.points + [touch.pos]
- else:
- shape.curve.points = shape.curve.points[:-1] + [touch.pos]
- return True
- return super(Canvas, self).on_touch_move(touch)
- def on_touch_up(self, touch):
- if 'shape' in touch.userdata:
- shape = touch.userdata['shape']
- if len(shape.curve.curve) < 3:
- self.remove_widget(shape)
- return
- shape.curve.is_closed = True
- shape.curve.update()
- return True
- return super(Canvas, self).on_touch_up(touch)
- runTouchApp(Canvas())
Add Comment
Please, Sign In to add comment