From 58ba101382337d91047de081b3f9efc97d055908 Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Tue, 18 Oct 2011 21:49:13 +0200 Subject: [PATCH] examples: add a tiny widget with custom shape and custom collide_point method. --- examples/widgets/customcollide.py | 81 +++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 examples/widgets/customcollide.py diff --git a/examples/widgets/customcollide.py b/examples/widgets/customcollide.py new file mode 100644 index 000000000..1180edc0e --- /dev/null +++ b/examples/widgets/customcollide.py @@ -0,0 +1,81 @@ +''' +Custom shape & collide widget +============================= + +This is a Triangle widget with a triangle shape based on 3 points (p1, p2, p3), +plus a custom collision function. + +The p1, p2, p3 are automatically calculated from the position and the size of +the Widget bounding box. We are using them to draw the triangle shape. +(Please note in the kv the special case for Scatter.) + +Then, we need to setup a new collision function to collide only on the triangle. +We are using a external method that will check if a point is inside a polygon +(we consider our triangle as a polygon). +''' + + +import kivy +kivy.require('1.0.8') + +from kivy.uix.scatter import Scatter +from kivy.properties import ListProperty +from kivy.lang import Builder + + +Builder.load_string(''' +: + # example for doing a triangle + # this will automatically recalculate pX from pos/size + p1: 0, 0 + p2: self.width, 0 + p3: self.width / 2, self.height + + # If you use a Widget instead of Scatter as base class, you need that: + #p1: self.pos + #p2: self.right, self.y + #p3: self.center_x, self.top + + # draw something + canvas: + Color: + rgb: 1, 0, 0 + Triangle: + points: self.p1 + self.p2 + self.p3 +''') + + +def point_inside_polygon(x, y, poly): + '''Taken from http://www.ariel.com.au/a/python-point-int-poly.html + ''' + n = len(poly) + inside = False + p1x = poly[0] + p1y = poly[1] + for i in xrange(0, n + 2, 2): + p2x = poly[i % n] + p2y = poly[(i + 1) % 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 Triangle(Scatter): + p1 = ListProperty([0, 0]) + p2 = ListProperty([0, 0]) + p3 = ListProperty([0, 0]) + + def collide_point(self, x, y): + x, y = self.to_local(x, y) + return point_inside_polygon(x, y, + self.p1 + self.p2 + self.p3) + +if __name__ == '__main__': + from kivy.base import runTouchApp + runTouchApp(Triangle(size_hint=(None, None)))