summaryrefslogtreecommitdiff
path: root/host/simu/inter
diff options
context:
space:
mode:
authorNicolas Schodet2009-03-14 15:57:17 +0100
committerNicolas Schodet2009-03-14 15:57:17 +0100
commit233c384c6c53f91e1405d797d9683f3296ddabc1 (patch)
tree4c212e546b0456edd6d2d7e1b18742bae86c7885 /host/simu/inter
parent1a5e89e4030e9bb4118caebd3fdee7bd6224277c (diff)
* host/inter, host/simu:
- moved drawable and trans_matrix to the new directory structure. - new drawable behaviour.
Diffstat (limited to 'host/simu/inter')
-rw-r--r--host/simu/inter/__init__.py0
-rw-r--r--host/simu/inter/drawable.py210
-rw-r--r--host/simu/inter/test/test_drawable.py65
3 files changed, 275 insertions, 0 deletions
diff --git a/host/simu/inter/__init__.py b/host/simu/inter/__init__.py
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/host/simu/inter/__init__.py
diff --git a/host/simu/inter/drawable.py b/host/simu/inter/drawable.py
new file mode 100644
index 00000000..6f04ffd8
--- /dev/null
+++ b/host/simu/inter/drawable.py
@@ -0,0 +1,210 @@
+# inter - Robot simulation interface. {{{
+#
+# Copyright (C) 2008 Nicolas Schodet
+#
+# APBTeam:
+# Web: http://apbteam.org/
+# Email: team AT apbteam DOT org
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# }}}
+"""Drawable and DrawableCanvas."""
+from math import sqrt, degrees
+import simu.utils.trans_matrix
+import Tkinter
+
+__all__ = ('Drawable', 'DrawableCanvas')
+
+class Drawable:
+ """Define a drawable area with embedded transformations."""
+
+ def __init__ (self, onto):
+ """Initialise the drawable."""
+ self.__onto = onto
+ self.__trans_matrix = simu.utils.trans_matrix.TransMatrix ()
+ self.__items = [ ]
+ self.trans_apply = self.__trans_matrix.apply
+ self.trans_apply_angle = self.__trans_matrix.apply_angle
+ self.trans_apply_distance = self.__trans_matrix.apply_distance
+ self.trans_rotate = self.__trans_matrix.rotate
+ self.trans_translate = self.__trans_matrix.translate
+ self.trans_scale = self.__trans_matrix.scale
+ self.trans_identity = self.__trans_matrix.identity
+ self.__children = [ ]
+ self.children = self.__children
+ self.__onto.__children.append (self)
+
+ def __draw_rectangle (self, p1, p2, **kw):
+ if 'outline' not in kw:
+ kw = kw.copy ()
+ kw['outline'] = 'black'
+ p = self.trans_apply (p1, (p2[0], p1[1]), p2, (p1[0], p2[1]))
+ return self.__onto.__draw_polygon (*p, **kw)
+
+ def __draw_line (self, *p, **kw):
+ p = self.trans_apply (*p)
+ return self.__onto.__draw_line (*p, **kw)
+
+ def __draw_polygon (self, *p, **kw):
+ p = self.trans_apply (*p)
+ return self.__onto.__draw_polygon (*p, **kw)
+
+ def __draw_circle (self, p, r, **kw):
+ p = self.trans_apply (p)
+ r = self.trans_apply_distance (r)
+ return self.__onto.__draw_circle (p, r, **kw)
+
+ def __draw_arc (self, p, r, **kw):
+ p = self.trans_apply (p)
+ r = self.trans_apply_distance (r)
+ if 'start' in kw:
+ kw = kw.copy ()
+ kw['start'] = self.trans_apply_angle (kw['start'])
+ import math
+ return self.__onto.__draw_arc (p, r, **kw)
+
+ def draw_rectangle (self, *p, **kw):
+ """Draw a rectangle."""
+ self.__items.append (self.__draw_rectangle (*p, **kw))
+
+ def draw_line (self, *p, **kw):
+ """Draw a line."""
+ self.__items.append (self.__draw_line (*p, **kw))
+
+ def draw_polygon (self, *p, **kw):
+ """Draw a line."""
+ self.__items.append (self.__draw_polygon (*p, **kw))
+
+ def draw_circle (self, p, r, **kw):
+ """Draw a circle of the given radius centered on p."""
+ self.__items.append (self.__draw_circle (p, r, **kw))
+
+ def draw_arc (self, p, r, **kw):
+ """Draw a arc of the given radius centered on p."""
+ self.__items.append (self.__draw_arc (p, r, **kw))
+
+ def reset (self):
+ """Clear all drawn items, reset transformations."""
+ for i in self.__children:
+ i.reset ()
+ self.__delete (*self.__items)
+ self.__items = [ ]
+ self.trans_identity ()
+
+ def __delete (self, *list):
+ """Delete a list of items."""
+ self.__onto.__delete (*list)
+
+ def update (self, *list):
+ """Add provided arguments to update list, or self if no argument
+ provided."""
+ if list:
+ self.__onto.update (*list)
+ else:
+ self.__onto.update (self)
+
+ def draw (self):
+ """Default drawing method which redraw every children."""
+ if self.__children:
+ self.update (*self.__children)
+
+
+class DrawableCanvas(Tkinter.Canvas):
+ """Extend a Tkinter.Canvas to use Drawable on it. Children are drawn on
+ redraw."""
+
+ def __init__ (self, width, height, xorigin, yorigin, master = None, **kw):
+ """Initialise a DrawableCanvas. The width and height parameters
+ define the requested drawable area virtual size. The xorigin and
+ yorigin parameters define origin of the virtual coordinates relative
+ to the drawable center."""
+ Tkinter.Canvas.__init__ (self, master, **kw)
+ self.__width = width
+ self.__height = height
+ self.__xorigin = xorigin
+ self.__yorigin = yorigin
+ self.bind ('<Configure>', self.__resize)
+ self.__updated = [ ]
+ self._Drawable__children = [ ]
+
+ def __resize (self, ev):
+ # Compute new scale.
+ w, h = float (ev.width), float (ev.height)
+ self.__scale = min (w / self.__width, h / self.__height)
+ self.__xoffset = w / 2 + self.__xorigin * self.__scale
+ self.__yoffset = h / 2 - self.__yorigin * self.__scale
+ # Redraw.
+ self.draw ()
+
+ def _Drawable__draw_line (self, *p, **kw):
+ p = self.__coord (*p)
+ return self.create_line (*p, **kw)
+
+ def _Drawable__draw_polygon (self, *p, **kw):
+ p = self.__coord (*p)
+ return self.create_polygon (*p, **kw)
+
+ def _Drawable__draw_circle (self, p, r, **kw):
+ p, = self.__coord (p)
+ r = r * self.__scale
+ p1 = (p[0] - r, p[1] - r)
+ p2 = (p[0] + r, p[1] + r)
+ return self.create_oval (p1, p2, **kw)
+
+ def _Drawable__draw_arc (self, p, r, **kw):
+ p, = self.__coord (p)
+ r = r * self.__scale
+ p1 = (p[0] - r, p[1] - r)
+ p2 = (p[0] + r, p[1] + r)
+ for k in ('start', 'extent'):
+ if k in kw:
+ kw = kw.copy ()
+ kw[k] = degrees (kw[k])
+ return self.create_arc (p1, p2, **kw)
+
+ def _Drawable__delete (self, *list):
+ self.delete (*list)
+
+ def update (self, *list):
+ """If called with arguments, add them to the update list.
+ Else, redraw all element in the update list."""
+ if list:
+ for i in list:
+ if i not in self.__updated:
+ self.__updated.append (i)
+ else:
+ while self.__updated:
+ updated = self.__updated
+ self.__updated = [ ]
+ for i in updated:
+ i.draw ()
+
+ def draw (self):
+ """Default drawing method which redraw every children."""
+ if self._Drawable__children:
+ self.update (*self._Drawable__children)
+ self.update ()
+
+ def __coord (self, *args):
+ return [ (i[0] * self.__scale + self.__xoffset,
+ -i[1] * self.__scale + self.__yoffset) for i in args ]
+
+ def screen_coord (self, screen):
+ """Return drawable coordinates corresponding to the given screen
+ coordinates."""
+ return ((self.canvasx (screen[0]) - self.__xoffset) / self.__scale,
+ -(self.canvasy (screen[1]) - self.__yoffset) / self.__scale)
+
diff --git a/host/simu/inter/test/test_drawable.py b/host/simu/inter/test/test_drawable.py
new file mode 100644
index 00000000..f67cb144
--- /dev/null
+++ b/host/simu/inter/test/test_drawable.py
@@ -0,0 +1,65 @@
+# inter - Robot simulation interface. {{{
+#
+# Copyright (C) 2008 Nicolas Schodet
+#
+# APBTeam:
+# Web: http://apbteam.org/
+# Email: team AT apbteam DOT org
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# }}} */
+from math import pi
+
+from simu.inter.drawable import *
+
+class Test (Drawable):
+
+ def draw (self):
+ self.draw_rectangle ((-100, -100), (100, 100), fill = '', outline = 'gray')
+ self.draw_rectangle ((0, 0), (5, 5), fill = 'red')
+ self.draw_rectangle ((20, 20), (50, 50), fill = '', outline = 'blue')
+ self.draw_line ((20, 20), (25, 25), (80, 0), (0, 80), fill = 'green')
+ self.draw_line ((20, 20), (25, 25), (80, 0), (0, 80), smooth = True)
+ self.draw_circle ((40, -40), 10)
+ self.draw_arc ((-40, 0), 20, start = pi / 4, extent = pi / 2)
+
+class App (DrawableCanvas):
+
+ def __init__ (self, master = None):
+ DrawableCanvas.__init__ (self, 300, 300, 20, 20, master)
+ self.pack (expand = True, fill = 'both')
+ self.test = Test (self)
+ self.animated = False
+ self.i = 0
+
+ def animate (self):
+ # Real user should reset at each redraw.
+ self.after (500, self.animate)
+ self.test.draw ()
+ self.test.trans_rotate (-pi/12)
+ self.test.trans_translate ((10, 10))
+ self.test.trans_scale (1.05)
+ self.i += 1
+ if self.i == 10:
+ self.test.reset ()
+
+ def draw (self):
+ if not self.animated:
+ self.animate ()
+ self.animated = True
+
+app = App ()
+app.mainloop ()