aboutsummaryrefslogtreecommitdiff
path: root/Python
diff options
context:
space:
mode:
authorAchil2022-09-06 18:56:51 +0200
committerAchil2022-09-06 18:56:51 +0200
commit5bce61c04e589e368d534c4797711ac73c1e1f23 (patch)
tree299f2b64723a5c9697937f651cecf1416604baad /Python
parentb60b3de318b4e621518681cc2824b4d9c605ae9e (diff)
downloadtkzinc-5bce61c04e589e368d534c4797711ac73c1e1f23.zip
tkzinc-5bce61c04e589e368d534c4797711ac73c1e1f23.tar.gz
tkzinc-5bce61c04e589e368d534c4797711ac73c1e1f23.tar.bz2
tkzinc-5bce61c04e589e368d534c4797711ac73c1e1f23.tar.xz
Daniel Etienne pre release for Bullseye
Diffstat (limited to 'Python')
-rwxr-xr-xPython/build/lib.linux-x86_64-2.7/Zinc/Zinc.py1597
-rwxr-xr-xPython/build/lib.linux-x86_64-2.7/Zinc/__init__.py4
-rwxr-xr-xPython/build/lib.linux-x86_64-2.7/Zinc/geometry.py410
-rwxr-xr-xPython/build/lib.linux-x86_64-2.7/Zinc/graphics.py2351
-rwxr-xr-xPython/build/lib.linux-x86_64-2.7/Zinc/pictorial.py766
-rw-r--r--Python/demos/testGraphics.py2
-rw-r--r--Python/library/Zinc.py6
-rw-r--r--Python/library/graphics.py2
8 files changed, 5133 insertions, 5 deletions
diff --git a/Python/build/lib.linux-x86_64-2.7/Zinc/Zinc.py b/Python/build/lib.linux-x86_64-2.7/Zinc/Zinc.py
new file mode 100755
index 0000000..d5a276d
--- /dev/null
+++ b/Python/build/lib.linux-x86_64-2.7/Zinc/Zinc.py
@@ -0,0 +1,1597 @@
+#!/usr/bin/python
+# -*- coding: iso-8859-1 -*-
+#
+# Zinc.py -- Python interface to the tkzinc widget.
+#
+# Authors : Frederic Lepied, Patrick Lecoanet
+# Created Date : Thu Jul 22 09:36:04 1999
+#
+# $Id: Zinc.py 1908 2008-09-15 09:38:54Z lecoanet $
+#
+#
+# Copyright (c) 1999 CENA --
+#
+# See the file "Copyright" for information on usage and redistribution
+# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+#
+#
+
+__version__ = "$Revision: 1908 $"
+__revision__ = "$Revision: 1908 $"
+
+from Tkinter import *
+import new
+import os
+import locale, types
+import traceback
+
+ZINC_CURRENT_POSITION = -2
+ZINC_SPEED_VECTOR = -3
+ZINC_LEADER = -4
+ZINC_CONNECTION = -5
+_LIBLOADED = 0
+_VERSION = ""
+ZINC_NO_PART = ""
+
+# current part dictionnary
+ZINC_DPART = { 'position' : ZINC_CURRENT_POSITION,
+ 'speedvector' : ZINC_SPEED_VECTOR ,
+ 'leader' : ZINC_LEADER,
+ 'connection' : ZINC_CONNECTION}
+# notes : 'field' will be return when currentpart is a field
+
+def havetkzinc( window ):
+ '''load Zinc dynamic sharable object library , test if everything is ok
+if ok :return zinc version
+if nok : return 0 '''
+ global _LIBLOADED
+ global _VERSION
+ if ( _LIBLOADED == 1 ) :
+ return _VERSION
+ try:
+ if os.environ.has_key( 'auto_path' ):
+ ldir = os.environ['auto_path'].split( ':' )
+ ldir.reverse()
+ for adir in ldir :
+ window.tk.call( 'eval',
+ "set auto_path "
+ + "[linsert $auto_path 0 %s]" % ( adir ) )
+ window.tk.call( 'eval', 'package require Tkzinc' )
+ # Call a function from the package to autoload it
+ # and verify that all is OK.
+ sversion = window.tk.call( 'zinc' ) + " Zinc.py %s" % __version__
+ except TclError:
+ traceback.print_exc()
+ return 0
+ _LIBLOADED = 1
+ _VERSION = sversion
+ return sversion
+
+class ZincException:
+ def __call__( self ):
+ raise self
+
+ def __init__( self, message ):
+ self.message = message
+
+ def __str__( self ):
+ return self.message
+
+class Zinc( Widget ):
+ def __str__( self ):
+ return( "Zinc instance" )
+ def __init__( self, master = None, cnf = None, **kw ):
+ if kw.has_key( 'backward_compatibility' ):
+ self.currentpart = self.__oldcurrentpart
+ self.configure = self.__oldconfigure
+ self.scale = self.__oldscale
+ self.translate = self.__oldtranslate
+ del kw['backward_compatibility']
+ #Pour éviter des effets de bord
+ #si on met comme valeur par défaut de cnf
+ #à {}
+ if cnf is None :
+ cnf = {}
+ if master :
+ self.version = havetkzinc( master )
+ else:
+ master = Frame()
+ master.pack()
+ self.version = havetkzinc( master )
+ Widget.__init__( self, master, 'zinc', cnf, kw )
+ self.items = {}
+ #BootStrap Root
+ classe = eval( 'Group' )
+ obj = None
+ kw['id'] = 1
+ obj = new.instance( classe, kw )
+ self.items[1] = obj
+
+ def mainloop( self ):
+ """
+ Run the events mainloop
+ """
+ self.tk.mainloop()
+
+ def add( self, itemType, *args, **kw ):
+ """
+ listTypes = zinc.add()
+ id = zinc.add(type, group)
+ id = zinc.add(type, group, initargs, **options)
+ type=[arc|curve|rectangle|triangles|tabular|track|waypoint|group|icon|map|reticle|text|window]
+ """
+ args = list( args )
+ args = args+list( self._options( kw ) )
+ try:
+ return self.tk.getint(
+ self.tk.call( self._w, 'add', itemType, *args ) )
+ except TclError, excpt :
+ ZincException( "%s\nType %s\nArgs : %s"%( excpt, itemType, args ) )()
+
+ def addtag( self, *args ):
+ """
+ zinc.addtag(tag, searchSpec)
+ This command add the given tag to all items matching
+ the search specification.
+ If the tag is already present on some item,
+ nothing is done for that item.
+ The command has no effect if no item satisfy
+ the given criteria. The command returns an empty string.
+ """
+ self.tk.call( self._w, 'addtag', *args )
+
+ def addtag_above( self, newtag, tagOrId ):
+ """
+ zinc.addtag_above(tag, tagOrId)
+ """
+ self.addtag( newtag, 'above', tagOrId )
+
+ def addtag_all( self, newtag ):
+ """
+ A ne plus utiliser
+ Utiliser addtag_withtag
+ """
+ self.addtag( newtag, 'all' )
+
+ def addtag_ancestors( self, newtag, tagOrId, *ltagOrId ):
+ """
+ zinc.addtag_ancestors(tag, tagOrId, *listTagOrId)
+ """
+ self.addtag( newtag, 'ancestors', tagOrId, *ltagOrId )
+
+ def addtag_atpriority( self, newtag, pri, tagOrId = 1 ):
+ """
+ zinc.addtag_atpriority(tag, priority, tagOrId = 1)
+ """
+
+ self.addtag( newtag, 'atpriority', pri, tagOrId )
+
+ def addtag_below( self, newtag, tagOrId ):
+ """
+ zinc.addtag_below(tag, tagOrId)
+ """
+ self.addtag( newtag, 'below', tagOrId )
+
+ def addtag_closest( self, newtag, x, y, halo = None, startItem = 1, recursive = 0 ):
+ """
+ zinc.addtag_closest(tag, x, y, halo = None, startItem = 1, recursive = 0)
+ """
+ self.addtag( newtag, 'closest', x, y, halo, startItem, recursive )
+
+ def addtag_enclosed( self, newtag, x1, y1, x2, y2, inGroup = 1, recursive = 0 ):
+ """
+ zinc.addtag_enclosed(tag, x1, y1, x2, y2, inGroup = 1, recursive = 0)
+ """
+ self.addtag( newtag, 'enclosed', x1, y1, x2, y2, inGroup, recursive )
+
+ def addtag_overlapping( self, newtag, x1, y1, x2, y2, inGroup = 1, recursive = 0 ):
+ """
+ zinc.addtag_overlapping(tag, x1, y1, x2, y2, inGroup = 1, recursive = 0)
+ """
+ self.addtag( newtag, 'overlapping', x1, y1, x2, y2, inGroup, recursive )
+
+ def addtag_withtag( self, newtag, tagOrId ):
+ """
+ zinc.addtag_withtag(tag, tagOrId)
+ """
+ self.addtag( newtag, 'withtag', tagOrId )
+
+ def addtag_withtype( self, newtag, type, tagOrId = 1 ):
+ """
+ zinc.addtag_withtype(tag, type, tagOrId = 1)
+ """
+ self.addtag( newtag, 'withtype', type, tagOrId )
+
+ def anchorxy( self, *args ):
+ """
+ (x, y) = zinc.anchorxy(tagOrId, anchor)
+ """
+ return self.tk.call( self._w, 'anchorxy', *args )
+
+ def bbox( self, *args ):
+ """
+ (xo, yo, xc, yc) = zinc.bbox(tagOrId, ?fieldIndex?)
+ """
+ return self.tk.call( self._w, 'bbox', *args )
+
+ def becomes( self ):
+ """
+ zinc.becomes()
+ """
+ self.tk.call( self._w, 'becomes' )
+
+ def bind_tag( self, tagOrId, sequence = None, func = None, add = None ):
+ '''
+ return a funcid which can be usefull for unbinding
+ listBindings = zinc.bind_tag(tagOrId)
+ listbindings = zinc.bind_tag(tagOrId, sequence)
+ zinc.bind_tag(tagOrId, sequence, '')
+ zinc.bind_tag(tagOrId, sequence, command)
+ '''
+ return self._bind( ( self._w, 'bind', tagOrId ),
+ sequence, func, add )
+
+ def cget( self, option ):
+ """
+ val = zinc.cget(option)
+ """
+ return self.tk.call( self._w, 'cget', '-' + option )
+
+ def chggroup( self, *args ):
+ """
+ zinc.chggroup(tagOrId, group, ?adjustTransform?)
+ """
+ self.tk.call( self._w, 'chggroup', *args )
+
+ def clone( self, *args, **kw):
+ """
+ id = zinc.clone(tagOrId, **attributs)
+ """
+ args = list( args ) + list( self._options( kw ) )
+ return self.tk.call( self._w, 'clone', *args)
+
+ def __oldconfigure( self, **kw ):
+ return Widget.configure( self, **kw )
+
+ def configure( self, **kw ):
+ """
+ listOptions = zinc.configurez()
+ listOptions = zinc.configurez(option)
+ zinc.configurez(**options)
+ """
+ res = Widget.configure( self, **kw )
+ dico = {}
+ if res:
+ for i, j in res.items():
+ dico[i] = j[3:]
+ return dico
+
+ def contour( self, *args ):
+ """
+ contourNum = zinc.contour(tagOrId)
+ contourNum = zinc.contour(tagOrId, operatorAndFlag, coordListOrTagOrId)
+ """
+ return self.tk.call( self._w, 'contour', *args )
+
+ def coords( self, *args ):
+ """
+ zinc.coords(tagOrId, contourIndex)
+ zinc.coords(tagOrId, contourIndex, coordList)
+ zinc.coords(tagOrId, contourIndex, coordIndex)
+ zinc.coords(tagOrId, contourIndex, coordIndex, coordList)
+ zinc.coords(tagOrId, 'remove', contourIndex, coordIndex)
+ zinc.coords(tagOrId, 'add', contourIndex, coordList)
+ zinc.coords(tagOrId, 'add', contourIndex, coordIndex, coordList)
+ zinc.coords(tagOrId)
+ zinc.coords(tagOrId, coordList)
+ zinc.coords(tagOrId, 'remove', coordIndex)
+ zinc.coords(tagOrId, 'add', coordList)
+ """
+ return self.tk.call( self._w, 'coords', *args )
+
+ def __buggyoldcurrentpart( self ):
+ '''
+ return a string (result from zinc current part function) and an
+ integer representing either the number of the field either
+ the number of the item part either ZINC_NO_PART
+ '''
+ scurrentp = self.tk.call( self._w, 'currentpart' )
+ if scurrentp == "":
+ rvalue = ZINC_NO_PART
+ else:
+ try:
+ rvalue = locale.atoi( scurrentp )
+ except:
+ try:
+ rvalue = ZINC_DPART[scurrentp]
+ except:
+ rvalue = ZINC_NO_PART
+ else:
+ # string to integer succeeded
+ scurrentp = "field"
+ return( scurrentp, rvalue )
+
+ def __oldcurrentpart( self ):
+ '''return a string and an integer ;
+the string is among "field", "position", "speedvector", "leader", "connection", "",
+the number is the number of the part , or the field number in case of "field";
+ex:
+no part return '', ZINC_NO_PART
+'''
+ scurrentp = self.tk.call( self._w, 'currentpart' )
+ print "Zinc::__oldcurrentpart scurrentp = [%s]" % scurrentp
+ # warning : read this first :
+ # return a string among 'position', 'speedvector', 'leader', 'connection' ,''
+ # or an int representing the number of a field label
+ #
+ # print "Zinc::currentpart cp=%s ,type(cp)=%s" % (scurrentp,type(scurrentp))
+ if scurrentp == "":
+ rvalue = ZINC_NO_PART
+ elif type( scurrentp ) == type( 1 ):
+ # meaning a field
+ # the subtil thing is here ! warning !
+ rvalue = scurrentp
+ scurrentp = "field"
+ else:
+ # scurrentp is a string different from ""
+ try:
+ rvalue = ZINC_DPART[scurrentp]
+ except:
+ print "Zinc::currentpart unknown item part"
+ rvalue = ZINC_NO_PART
+
+ return scurrentp, rvalue
+
+ def currentpart( self ):
+ '''
+ num = zinc.currentpart()
+ '''
+ return str( self.tk.call( self._w, 'currentpart' ) )
+
+
+ def cursor( self, *args ):
+ """
+ zinc.cursor(tagOrId, index)
+ """
+ self.tk.call( self._w, 'cursor', *args )
+
+ def dchars( self, *args ):
+ """
+ zinc.dchars( tagOrId, first )
+ zinc.dchars( tagOrId, first,last )
+ """
+ self.tk.call( self._w, 'dchars', *args )
+
+ def dtag( self, *args ):
+ """
+ zinc.dtag(tagOrId)
+ zinc.dtag(tagOrId, tagToDelete)
+ """
+ self.tk.call( self._w, 'dtag', *args )
+
+ def find( self, *args ):
+ return self._getints(
+ self.tk.call( self._w, 'find', *args ) ) or ()
+
+ def find_above( self, tagOrId ):
+ """
+ listItems=zinc.find_above(tagOrId)}
+ """
+ return self.find( 'above', tagOrId )
+
+ def find_all( self ):
+ return self.find( 'all' )
+
+ def find_ancestors( self, newtag, tagOrId, *tagOrId2 ):
+ """
+ listItems=zinc.find_ancestor(tag, tagOrId, ?tagOrId2?)
+ """
+ return self.find( newtag, 'ancestors', tagOrId, *tagOrId2 )
+
+ def find_atpriority( self, pri, *tagOrId ):
+ """
+ listItems=zinc.find_atpriority(pri, ?tagOrId?)
+ """
+ return self.find( 'atpriority', pri, *tagOrId )
+
+ def find_below( self, tagOrId ):
+ """
+ listItems=zinc.find_below(tagOrId)
+ """
+ return self.find( 'below', tagOrId )
+
+ def find_closest( self, x, y, *options ):
+ """
+ listItems=zinc.find_closest(x, y, ?halo?, ?startItem?, ?recursive?)
+ """
+ return self.find( 'closest', x, y, *options )
+
+ def find_enclosed( self, x1, y1, x2, y2 ):
+ """
+ listItems=zinc.find_enclosed(x1, y1, x2, y2, inGroup=1, recursive=0)
+ """
+ return self.find( 'enclosed', x1, y1, x2, y2 )
+
+ def find_overlapping( self, x1, y1, x2, y2, *options ):
+ """
+ listItems=zinc.find_overlapping( x1, y1, x2, y2, ?inGroup?, ?recursive?)
+ """
+ return self.find( 'overlapping', x1, y1, x2, y2, *options )
+
+ def find_withtag( self, tagOrId ):
+ """
+ listItems=zinc.find_withtag( tagOrId)
+ """
+ return self.find( 'withtag', tagOrId )
+
+ def find_withtype( self, type, *tagOrId ):
+ """
+ listItems=zinc.find_withtype( type, ?tagOrId?)
+ """
+ return self.find( 'withtype', type, *tagOrId )
+
+
+ def fit( self, *args ):
+ """
+ listControls=zinc.fit(coordList,error)
+ """
+ return self.tk.call( self._w, 'fit', *args )
+
+ def focus( self, *args ):
+ """
+ zinc.focus(tagOrId, ?itemPart?)
+ """
+ self.tk.call( self._w, 'focus', *args )
+
+ def gdelete( self, *args ):
+ """
+ zinc.gdelete(gradientName)
+ """
+ self.tk.call( self._w, 'gdelete', *args )
+
+ def gettags( self, *args ):
+ """
+ listTags=zinc.gettags(tagorid)
+ """
+ return self.tk.splitlist( self.tk.call( self._w, 'gettags', *args ) )
+
+ def gname( self, *args ):
+ """
+ zinc.gname(gradientDesc, gradientName)
+ bExist=zinc.gname(gradientName)
+ """
+ return self.tk.call( self._w, 'gname', *args )
+
+ def group( self, *args ):
+ """
+ group=zinc.group(tagOrId)
+ """
+ return self.tk.call( self._w, 'group', *args )
+
+ def hasanchors( self, *args ):
+ """
+ bool=zinc.hasanchors(tagOrId)
+ """
+ return self.tk.call( self._w, 'hasanchors', *args )
+
+ def hasfields( self, *args ):
+ """
+ bool=zinc.hasfields(tagOrId)
+ """
+ return self.tk.call( self._w, 'hasfield', *args )
+
+ def hastag( self, *args ):
+ """
+ bool=zinc.hastag(tagOrId, tag)
+ """
+ return self.tk.call( self._w, 'hastag', *args )
+
+ def index( self, *args ):
+ """
+ num = zinc.index(tagOrId, index)
+ """
+ return self.tk.call( self._w, 'tagOrId', *args )
+
+ def insert( self, *args ):
+ """
+ zinc.insert(tagOrId, before, string)
+ """
+ self.tk.call( self._w, 'insert', *args )
+
+ def itemcget( self, tagOrId, option ):
+ """
+ val=zinc.itemcget(tagOrId, attr)
+ """
+ return self.tk.call( self._w, 'itemcget', tagOrId, '-'+option )
+
+ def itemfieldget( self, tagOrId, field, option ):
+ """
+ val=zinc.itemcget(tagOrId, field, attr)
+ """
+ return self.tk.call( self._w, 'itemcget', tagOrId, field, '-'+option )
+
+ def itemconfigure( self, tagOrId, field=None, **kw ):
+ '''
+ either get the dictionnary of possible attributes (if kw is None)
+ either allow to set Items attributes or Field attributes
+
+ listAttribs=zinc.itemconfigure(tagOrId)
+ listAttribs=zinc.itemconfigure(tagOrId, attrib)
+ zinc.itemconfigure(tagOrId, **attributs)
+ listAttribs=zinc.itemconfigure(tagOrId, fieldIs, attrib)
+ zinc.itemconfigure(TagOrId,fieldId,**attributs)
+ '''
+ if not kw:
+ cnf = {}
+ for var_x in self.tk.split(
+ field != None and self.tk.call( self._w, 'itemconfigure',
+ ( tagOrId, field ) ) or
+ self.tk.call( self._w, 'itemconfigure', ( tagOrId, ) ) ):
+ cnf[var_x[0][1:]] = ( var_x[0][1:], ) + var_x[1:]
+ return cnf
+ if field != None:
+ args = ( tagOrId, str( field ), )+ self._options( {}, kw )
+ self.tk.call( self._w, 'itemconfigure', *args )
+ else:
+ args = ( tagOrId, ) + self._options( {}, kw )
+ self.tk.call( self._w, 'itemconfigure', *args )
+
+ # _dp voir si cette instruction est a execute ici
+ # permet de creer un synonyme de itemconfigure
+ itemconfig = itemconfigure
+
+ def loweritem( self, *args ):
+ """
+ zinc.loweritem(tagOrId)
+ zinc.loweritem(tagOrId, belowThis)
+ Reorder all the items given by tagOrId so that
+ they will be under the item given by belowThis.
+ If tagOrId name more than one item,
+ their relative order will be preserved.
+ If tagOrId doesn't name an item, an error is raised.
+ If belowThis name more than one item, the bottom most them is used.
+ If belowThis doesn't name an item, an error is raised.
+ If belowThis is omitted the items are put
+ at the bottom most position of their respective groups.
+ The command ignore all items named by tagOrId
+ that are not in the same group than belowThis or,
+ if not specified, in the same group than the first item
+ named by tagOrId. The command returns an empty string.
+ As a side affect of this command, the -priority attribute
+ of all the reordered items is ajusted to match the priority
+ of the belowThis item (or the priority of the bottom most item)
+ """
+ self.tk.call( self._w, 'lower', *args )
+
+ def monitor( self, *args ):
+ """
+ bool = zinc.monitor()
+ zinc.monitor(bool)
+ """
+ return self.tk.call( self._w, 'monitor', *args )
+
+ def numparts( self, *args ):
+ """
+ num = zinc.numparts(tagOrId)
+ """
+ return self.tk.call( self._w, 'numparts', *args )
+
+ def postcript( self, *args ):
+ """
+ Not Yet Implemented
+ zinc.postscript()
+ """
+ return self.tk.call( self._w, 'postscript', *args )
+
+ def raiseitem( self, *args ):
+ """
+ Correspond à l'appel raise de la documentation
+ le mot raise est reservé en python
+ zinc.raiseitem(tagOrId)
+ zinc.raiseitem(tagOrId, aboveThis)
+ """
+ self.tk.call( self._w, 'raise', *args )
+
+ def remove( self, *args ):
+ """
+ zinc.remove(tagOrId, ?tagOrId,...?)
+ """
+ self.tk.call( self._w, 'remove', *args )
+
+ def rotate( self, *args ):
+ """
+ zinc.rotate(tagOrId, angle)
+ zinc.rotate(tagOrId, angle, centerX, centerY)
+ """
+ self.tk.call( self._w, 'rotate', *args )
+
+ def __oldscale( self, xFactor=None, yFactor=None, tagOrId=None ):
+ if yFactor == None:
+ return self.tk.getdouble( self.tk.call( 'scale' ) )
+ else:
+ if tagOrId == None:
+ self.tk.call( self._w, 'scale', xFactor, yFactor )
+ else:
+ self.tk.call( self._w, 'scale', tagOrId, xFactor, yFactor )
+
+ def scale( self, *args ):
+ """
+ zinc.scale(tagOrIdOrTName, xFactor, yFactor)
+ zinc.scale(tagOrIdOrTName, xFactor, yFactor, centerX, centerY)
+ Add a scale factor to the items or the transform described
+ by tagOrId.
+ If tagOrId describes a named transform then this transform
+ is used to do the operation. If tagOrId describes more than
+ one item then all the items are affected by the operation.
+ If tagOrId describes neither a named transform nor an item,
+ an error is raised.
+ A separate factor is specified for X and Y.
+ The optional parameters describe the center of scaling,
+ which defaults to the origin.
+ """
+ if not len( args ):
+ return self.tk.getdouble( self.tk.call( self._w, 'scale' ) )
+ else:
+ self.tk.call( self._w, 'scale', *args )
+
+ def select( self, *args ):
+ """
+ zinc.select('adjust', tagOrId, index)
+ Adjust the end of the selection in tagOrId
+ that is nearest to the character given by index so
+ that it is at index.
+ The other end of the selection is made the anchor
+ for future select to commands.
+ If the selection is not currently in tagOrId,
+ this command behaves as the select to command.
+ The command returns an empty string.
+ zinc.select('clear')
+ Clear the selection if it is in the widget.
+ If the selection is not in the widget,
+ the command has no effect. Return an empty string.
+ zinc.select('from', tagOrId, index)
+ Set the selection anchor point for the widget
+ to be just before the character given by index
+ in the item described by tagOrId.
+ The command has no effect on the selection,
+ it sets one end of the selection so that future
+ select to can actually set the selection.
+ The command returns an empty string.
+ (item,part) = zinc.select('item')
+ Returns a list of two elements.
+ The first is the id of the selected item
+ if the selection is in an item on this widget;
+ Otherwise the first element is an empty string.
+ The second element is the part of the item
+ (track, waypoint or tabular item only) or the empty string.
+ zinc.select('to', tagOrId, index)
+ Set the selection to be the characters that lies
+ between the selection anchor and index in the item described
+ by tagOrId. The selection includes the character given
+ by index and includes the character given by the anchor point
+ if index is greater or equal to the anchor point.
+ The anchor point is set by the most recent select adjust
+ or select from command issued for this widget.
+ If the selection anchor point for the widget is not currently
+ in tagOrId, it is set to the character given by index.
+ The command returns an empty string.
+ Manipulates the selection as requested by option.
+ tagOrId describes the target item.
+ This item must support text indexing and selection. I
+ f more than one item is referred to by tagOrId,
+ the first in display list order that support both text
+ indexing and selection will be used.
+ Some forms of the command include an index parameter,
+ this parameter describes a textual position within the
+ item and should be a valid index as described in
+ Text indices.
+ """
+ return self.tk.call( self._w, 'select', *args )
+
+ def skew( self, *args ):
+ """
+ zinc.skew(tagOrIdOrTName,xSkewAngle, ySkewAngle)
+ Add a skew (or shear) transform to the to the items
+ or the transform described by tagOrIdOrTName.
+ If tagOrId describes a named transform then this transform
+ is used to do the operation.
+ If tagOrId describes more than one item then all the
+ items are affected by the operation.
+ If tagOrId describes neither a named transform nor an item,
+ an error is raised. The angles are given in radian.
+ """
+ return self.tk.call( self._w, 'skew', *args )
+
+ def smooth( self, *args ):
+ """
+ zinc.smooth(coordList)
+ This command computes a sequence of segments
+ that will smooth the polygon described by the vertices
+ in coordList and returns a list of lists describing points
+ of the generated segments. These segments are approximating
+ a Bezier curve. coordList should be either a flat list
+ of an even number of coordinates in x, y order, or a list
+ of lists of point coordinates X, Y.
+ The returned list can be used to create or change the contour
+ of a curve item.
+ """
+ return self.tk.call( self._w, 'smooth', *args )
+
+ def tapply( self, *args ):
+ """
+ Not Yet Implemented
+ zinc.tapply()
+ """
+ return self.tk.call( self._w, 'tapply', *args )
+
+ def tcompose( self, *args ):
+ """
+ zinc.tcompose(tagOrIdOrTName, tName)
+ zinc.tcompose(tagOrIdOrTName, tName, invert)
+ """
+ return self.tk.call( self._w, 'tapply', *args )
+
+ def tdelete( self, *args ):
+ """
+ zinc.tdelete(tName)
+ Destroy a named transform.
+ If the given name is not found among the named transforms,
+ an error is raised.
+ """
+ self.tk.call( self._w, 'tdelete', *args )
+
+ def transform( self, *args ):
+ """
+ listCoords=zinc.transform(tagOrIdTo, coordList)
+ listCoords=zinc.transform(tagOrIdFrom, tagOrIdTo, coordList)
+ This command returns a list of coordinates obtained by transforming the coordinates given in coordList
+ from the coordinate space of the transform or item described by tagOrIdFrom to the coordinate space
+ of the transform or item described by tagOrIdTo.
+ If tagOrIdFrom is omitted it defaults to the window coordinate space.
+ If either tagOrIdFrom or tagOrIdTo describes more than one item,
+ the topmost in display list order is used. If either tagOrIdFrom or tagOrIdTo
+ doesn't describe either a transform or an item, an error is raised.
+ The coordList should either be a flat list containing an even number of coordinates
+ each point having two coordinates, or a list of lists each sublist of the form [ X Y ?pointtype? ].
+ The returned coordinates list will be isomorphic to the list given as argument.
+
+ It is possible to convert from window coordinate space to the coordinate space of any item.
+ This is done by omitting ?tagOrIdFrom? and specifying in tagOrIdTo, the id of the item.
+ It can also be done by using the predefined tag 'device' as first argument.
+
+ It is also possible to convert from the coordinate space of an item to the window coordinate
+ space by using the predefined tag 'device' as second argument.
+
+ """
+ return self._getdoubles( self.tk.call( self._w, 'transform', *args ) )
+
+#ANCIENNE IMPLEMENTATION
+ def __oldtranslate( self, dx=None, dy=None, tagOrId=None ):
+ if dx == None:
+ return self._getints( self.tk.call( 'translate' ) )
+ else:
+ if tagOrId == None:
+ self.tk.call( self._w, 'translate', dx, dy )
+ else:
+ self.tk.call( self._w, 'translate', tagOrId, dx, dy )
+
+ def translate( self, *args ):
+ """
+ zinc.translate(tagOrIdOrTName, xAmount, yAmount)
+ zinc.translate(tagOrIdOrTName, xAmount, yAmount, absolute)
+ Add a translation to the items or the transform described by tagOrIdOrTName.
+ If tagOrIdOrTName describes a named transform then this transform is used
+ to do the operation.
+ If tagOrIdOrTName describes more than one item then all the items are affected
+ by the opration.
+ If tagOrIdOrTName describes neither a named transform nor an item,
+ an error is raised. A separate value is specified for X and Y.
+ If the optionnal ?absolute? parameter is true,
+ it will set an absolute translation to the tagOrIdOrTName
+ """
+ if ( len( args ) == 1 ):
+ return self._getints( self.tk.call( self._w, 'translate' ) )
+ else:
+ self.tk.call( self._w, 'translate', *args )
+
+ def treset( self, *args ):
+ """
+ zinc.treset(tagOrIdOrTName)
+ Set the named transform or the transform for the items described by tagOrIdOrTName
+ to identity. If tagOrIdOrTName describes neither a named transform nor an item,
+ an error is raised.
+ """
+ self.tk.call( self._w, 'treset', *args )
+
+ def trestore( self, *args ):
+ """
+ zinc.trestore(tagOrId, tName)
+ Set the transform for the items described by tagOrId to the transform named by tName.
+ If tagOrId doesn't describe any item or if the transform named tName doesn't exist,
+ an error is raised.
+ """
+ self.tk.call( self._w, 'trestore', *args )
+
+ def tsave( self, *args ):
+ """
+ zinc.tsave(tName)
+ zinc.tsave(tagOrIdOrTName, tName)
+ zinc.tsave(tagOrIdOrTName, tName, invert)
+ Create (or reset) a transform associated with the name tName
+ with initial value the transform associated with the item tagOrIdOrTName.
+ If tagOrIdOrTName describes more than one item, the topmost in display list order is used.
+ If tagOrIdOrTName doesn't describe any item or named transformation, an error is raised.
+ If tName already exists, the transform is set to the new value.
+ This command is the only way to create a named transform.
+ If tagOrIdOrTName is not specified, the command returns a boolean telling
+ if the name is already in use.
+ The invert boolean, if specified, cause the transform to be inverted prior to be saved.
+
+ It is possible to create a new named transformation from the identity
+ by using the predefined tag 'identity': $zinc->tsave('identity', 'myTransfo');
+ """
+ return self.tk.call( self._w, 'tsave', *args )
+
+ def tget( self, *args ):
+ """
+ zinc.tget(tagOrId)
+ zinc.tget(tagOrIdOrTName, selector)
+ selector:={'all'|'translation'|'scale'|'rotation'|'skew'}
+ With only one argument, get the six elements of the 3x4 matrix
+ used in affine transformation for tagOrIdOrTName.
+ The result is compatible with the tset method.
+ With optional second parameter 'all' returns the transform
+ decomposed in translation, scale, rotation, skew
+ and return the list in this order,
+ With 'translation', 'scale', 'rotation', 'skew' optional
+ second parameter, returns the corresponding values.
+ """
+ return self.tk.call( self._w, 'tget', *args )
+
+ def tset( self, *args ):
+ """
+ zinc.tset(tagOrIdOrName, m00, m01, m10, m11, m20, m21)
+ Set the six elements of the 3x4 matrix used in affine transformation for tagOrIdOrTName.
+ BEWARE that depending on mij values,
+ it is possible to define a not inversible matrix which will end up in core dump.
+ This method must BE USED CAUTIOUSLY.
+ """
+ return self.tk.call( self._w, 'tset', *args )
+
+ def type( self, tagOrId ):
+ """
+ name=zinc.type(tagOrId)
+ If more than one item is named by tagOrId,
+ then the type of the topmost item in display list order is returned.
+ If no items are named by tagOrId, an error is raised.
+ """
+ return self.tk.call( self._w, 'type', tagOrId )
+
+ def vertexat( self, *args ):
+ """
+ (contour,vertex,edgevertex)=zinc.vertexat(tagOrId,x,y)
+ """
+ return self.tk.call( self._w, 'vertexat', *args )
+
+ def xview(self, *args):
+ """Query and change horizontal position of the view."""
+ if not args:
+ return self._getdoubles(self.tk.call(self._w, 'xview'))
+ self.tk.call((self._w, 'xview') + args)
+ def xview_moveto(self, fraction):
+ """Adjusts the view in the window so that FRACTION of the
+ total width of the canvas is off-screen to the left."""
+ self.tk.call(self._w, 'xview', 'moveto', fraction)
+ def xview_scroll(self, number, what):
+ """Shift the x-view according to NUMBER which is measured in "units" or "pages" (WHAT)."""
+ self.tk.call(self._w, 'xview', 'scroll', number, what)
+ def yview(self, *args):
+ """Query and change vertical position of the view."""
+ if not args:
+ return self._getdoubles(self.tk.call(self._w, 'yview'))
+ self.tk.call((self._w, 'yview') + args)
+ def yview_moveto(self, fraction):
+ """Adjusts the view in the window so that FRACTION of the
+ total height of the canvas is off-screen to the top."""
+ self.tk.call(self._w, 'yview', 'moveto', fraction)
+ def yview_scroll(self, number, what):
+ """Shift the y-view according to NUMBER which is measured in "units" or "pages" (WHAT)."""
+ self.tk.call(self._w, 'yview', 'scroll', number, what)
+
+class ZincItem:
+ def __init__( self, zinc, itemType, group = 1, *args, **kw ):
+ self.zinc = zinc
+ texture = None
+ fillpatern = None
+ scale = None
+ translate = None
+ if kw.has_key( 'texture' ):
+ texture = kw['texture']
+ del kw['texture']
+
+ if kw.has_key( 'fillpatern' ):
+ fillpastern = kw['fillpatern']
+ del kw['fillpatern']
+
+ if kw.has_key( 'scale' ):
+ scale = kw['scale']
+ del kw['scale']
+
+ if kw.has_key( 'rotate' ):
+ rotate = kw['rotate']
+ del kw['rotate']
+
+ if kw.has_key( 'translate' ):
+ translate = kw['translate']
+ del kw['translate']
+
+ if kw.has_key( 'cloneid' ):
+ cloneid = kw['cloneid']
+ del kw['cloneid']
+ else:
+ cloneid = 0
+ group = str( group )
+ # sys.stdout.flush()
+ if cloneid == 0 :
+ self.id = zinc.add( itemType, group, *args, **kw )
+ else :
+ self.id = self.zinc.clone(cloneid, *args, **kw)
+
+ zinc.items[self.id] = self
+ texture = None
+ if fillpatern:
+ self.itemconfigure( fillpatern )
+ if scale:
+ self.scale( scale )
+ if translate:
+ self.translate( translate )
+
+
+ def __str__( self ):
+ return str( self.id )
+
+ def __repr__( self ):
+ return str( self.id )
+
+ def bbox( self, *args ):
+ return self.zinc.bbox( self.id, *args )
+
+ def clone( self, *args, **kw):
+ '''id = zincitem.clone(*args,**kw) '''
+ # print "ZincItem::clone"
+ # on cherche tagOrId
+ # nidcloned = self.find_above(tagOrId)
+ sclonedtype = self.type()
+ sclonedgroupid = self.zinc.group(self.id)
+
+ # ajout cle 'cloneid' (voir ZincItem::__init__)
+ kw['cloneid'] = self.id
+ # on cree un nouveau ZincItem meme type,
+ return(ZincItem(self.zinc, sclonedtype, sclonedgroupid, **kw ))
+
+ def delete( self ):
+ del self.zinc.items[self.id]
+ try:
+ self.zinc.remove( self.id )
+ except:
+ pass
+ def __getitem__( self, key ):
+ '''allow to get attribute by self["key"] '''
+ if ( key == "coords" ):
+ return self.zinc.coords( self.id )
+ return self.zinc.itemcget( self.id, key )
+
+ def __setitem__( self, key, value ):
+ '''allow to set item attrbutes, eg. for a track position attributes
+ just writing :
+ a = ZincItem(myzinc, ...)
+ a["position"] = (x,y)
+ Notes : when setting multiple attributes
+ using itemconfigure is more efficient '''
+ if ( key is "coords" ):
+ self.zinc.coords( self.id, value )
+ else:
+ self.zinc.itemconfigure( self.id, **{key:value} )
+
+ def getGroup( self ):
+ groupid = self.zinc.group( self.id )
+ return self.zinc.items[groupid]
+
+ def keys( self ):
+ if not hasattr( self, '_keys' ):
+ self._keys = {}
+ config = self.zinc.itemconfig( self.id )
+ for x in config.keys():
+ self._keys[x] = config[x][1]
+ return self._keys
+
+ def has_key( self, key ):
+ return key in self.keys()
+
+ def bind( self, sequence=None, command=None, add=None ):
+ '''return a funcid which can be used to unbind
+notes: unbinding can be done by bind("<seq>","") or using native tkinter
+unbind method '''
+ return( self.zinc.bind_tag( self.id, sequence, command, add ) )
+
+ def cget( self, attr ):
+ return self.zinc.itemcget( self.id, attr )
+
+ def coords( self, *args, **kw ):
+ return self.zinc.coords( self.id, *args, **kw )
+
+ def fieldcget( self, field, attr ):
+ return self.zinc.itemfieldcget( self.id, field, attr )
+
+ def itemconfigure( self, field=None, **kw ):
+ self.zinc.itemconfigure( self.id, field, **kw )
+
+ def rotate( self, *args ):
+ return self.zinc.rotate( self.id, *args )
+
+ def scale( self, *args ):
+ return self.zinc.scale( self.id, *args )
+
+ def transforms( self, *args ):
+ """
+ zincitem.transform(tozincitem, coordList)
+ This command returns a list of coordinates obtained by transforming the coordinates given in coordList
+ from the coordinate space of item to the coordinate space
+ of the tozincitem item.
+ The coordList should either be a flat list containing an even number of coordinates
+ each point having two coordinates, or a list of lists each sublist of the form [ X Y ?pointtype? ].
+ The returned coordinates list will be isomorphic to the list given as argument.
+ """
+ return self.zinc.transforms( self.id, *args )
+
+ def translate( self, *args ):
+ """
+ zincitem.translate( xAmount, yAmount)
+ zincitem.translate( xAmount, yAmount, absolute)
+ Add a translation to the item.
+ A separate value is specified for X and Y.
+ If the optionnal ?absolute? parameter is true,
+ it will set an absolute translation to the item
+ """
+ self.zinc.translate( self.id, *args )
+
+ def tset( self, *args ):
+ """
+ zincitemtset(m00, m01, m10, m11, m20, m21)
+ Set the six elements of the 3x4 matrix used in affine transformation.
+ BEWARE that depending on mij values,
+ it is possible to define a not inversible matrix which will end up in core dump.
+ This method must BE USED CAUTIOUSLY.
+ """
+ self.zinc.tset( self.id, *args )
+
+ def type( self ):
+ """
+ name=zincitemtype()
+ This command returns the type of the item.
+ """
+ return self.zinc.type( self.id )
+
+ def tsave( self, *args ):
+ """
+ zincitemtsave( tName)
+ zincitemtsave( tName, invert)
+ Create a transform associated with the name tName
+ with initial value the transform associated with the item.
+ If tName already exists, the transform is set to the new value.
+ This command is the only way to create a named transform.
+ The invert boolean, if specified, cause the transform to be inverted prior to be saved.
+ """
+ return self.zinc.tsave( self.id, *args )
+
+ def treset( self, *args ):
+ """
+ zincitemtreset()
+ Set the named transform or the transform for the item
+ to identity. If there are no named transform,
+ an error is raised.
+ """
+ self.zinc.treset( self.id, *args )
+
+ def trestore( self, *args ):
+ """
+ zincitemtrestore( tName)
+ Set the transform for the item to the transform named by tName.
+ If the transform named tName doesn't exist, an error is raised.
+ """
+ self.zinc.trestore( self.id, *args )
+
+ def tget( self, *args ):
+ """
+ zincitemtget()
+ zincitemtget(selector)
+ selector:={'all'|'translation'|'scale'|'rotation'|'skew'}
+ With only one argument, get the six elements of the 3x4 matrix
+ used in affine transformation.
+ The result is compatible with the tset method.
+ With optional second parameter 'all' returns the transform
+ decomposed in translation, scale, rotation, skew
+ and return the list in this order,
+ With 'translation', 'scale', 'rotation', 'skew' optional
+ second parameter, returns the corresponding values.
+ """
+ return self.zinc.tget( self.id, *args )
+
+
+class Arc( ZincItem ):
+ def __init__( self, zinc, *args, **kw ):
+ """
+ The arc type expects a list of four floating point numbers xo yo xc yc,
+ giving the coordinates of the origin and the corner of the enclosing rectangle.
+ The origin should be the top left vertex of the enclosing rectangle and the corner
+ the bottom right vertex of the rectangle.
+ """
+ ZincItem.__init__( self, zinc, 'arc', *args, **kw )
+
+class Group( ZincItem ):
+ def __init__( self, zinc, *args, **kw ):
+ """
+ These type do not expect type specific arguments.
+ """
+ ZincItem.__init__( self, zinc, 'group', *args, **kw )
+
+ def getGroup( self ):
+ """Retourne l'objet de type Group
+ auquel est attache l'item"""
+ ###Gestion du boostrap
+ if self.id == 1:
+ return self.zinc.items[1]
+ else:
+ return ZincItem.getGroup( self )
+
+ #TODO: Extension. Renvoie les références aux ZincItems contenus dans le Groupe
+ def getNode( self ):
+ """
+ """
+ pass
+
+class Icon( ZincItem ):
+ def __init__( self, zinc, *args, **kw ):
+ """
+ These type do not expect type specific arguments.
+ """
+ ZincItem.__init__( self, zinc, 'icon', *args, **kw )
+
+class Map( ZincItem ):
+ def __init__( self, zinc, *args, **kw ):
+ """
+ These type do not expect type specific arguments.
+ """
+ ZincItem.__init__( self, zinc, 'map', *args, **kw )
+
+class Curve( ZincItem ):
+ def __init__( self, zinc, *args, **kw ):
+ """
+ The curve type expects either a flat list or a list of lists.
+ In the first case, the flat list must be a list of floating point numbers
+ x0 y0 x1 y1 ... xn yn, giving the coordinates of the curve vertices.
+ The number of values should be even (or the last value will be discarded)
+ but the list can be empty to build an empty invisible curve.
+ In the second case,thelist must contain lists of 2 or 3 elements:
+ xi, yi and and an optionnal point type. Currently,
+ the only available point type is 'c' for a cubic bezier control point.
+ For example, the following list is an example of 2 beziers segments
+ with a straight segment in-between:
+ ( [x0, y0], [x1, y1, 'c'], [x2, y2, 'c'], [x3, y3], [x4, y4, 'c'], [x5, y5] )
+
+ As there is only on control point, [x4, y4, 'c'] ,
+ for the second cubic bezier,
+ the omitted second control point will be defaulted to the same point.
+ a named tuple contours can give to define new contours in curve.
+ contours=(<contour1>,...)
+ <contour>=(<point1>,...)
+ A curve can be defined later with the contour or coords commands.
+ As a side effect of the curve behavior,
+ a one vertex curve is essentially the same as an empty curve,
+ it only waste some more memory.
+
+ """
+ contours = []
+ if kw.has_key( 'contours' ):
+ contours = kw['contours']
+ del kw['contours']
+ ZincItem.__init__( self, zinc, 'curve', *args, **kw )
+ for contour in contours:
+ self.zinc.contour( self.id, *contour )
+
+
+class Rectangle( ZincItem ):
+ def __init__( self, zinc, *args, **kw ):
+ """
+ The rectangle type expects a list of four floating point numbers xo yo xc yc,
+ giving the coordinates of the origin and the corner of the rectangle.
+ """
+ ZincItem.__init__( self, zinc, 'rectangle', *args, **kw )
+
+class Reticle( ZincItem ):
+ def __init__( self, zinc, *args, **kw ):
+ """
+ These type do not expect type specific arguments.
+ """
+ ZincItem.__init__( self, zinc, 'reticle', *args, **kw )
+
+class Tabular( ZincItem ):
+ def __init__( self, zinc, *args, **kw ):
+ ZincItem.__init__( self, zinc, 'tabular', *args, **kw )
+
+class Text( ZincItem ):
+ def __init__( self, zinc, *args, **kw ):
+ """
+ These type do not expect type specific arguments.
+ """
+ ZincItem.__init__( self, zinc, 'text', *args, **kw )
+
+class Track( ZincItem ):
+ def __init__( self, zinc, *args, **kw ):
+ ZincItem.__init__( self, zinc, 'track', *args, **kw )
+
+class WayPoint( ZincItem ):
+ def __init__( self, zinc, *args, **kw ):
+ ZincItem.__init__( self, zinc, 'waypoint', *args, **kw )
+
+
+# Class to hold mapinfos used by the Map Item class
+class Mapinfo:
+ def __init__( self, interp, name = None ):
+ """
+ @type name: string
+ @param name: Name of mapinfo. Must be used carrefully !
+ Create a new empty map description.
+ The new mapinfo object named name or internal id if name is omitted
+ """
+ if name :
+ self.name = name
+ else:
+ self.name = `id( self )`
+ self.interp = interp.tk
+ apply( self.interp.call, ( 'mapinfo', self.name, 'create' ) )
+
+ def __repr__( self ):
+ return self.name
+
+ def __del__( self ):
+ self.delete()
+
+ def delete( self ):
+ """
+ Delete the mapinfo object.
+ All maps that refer to the deleted mapinfo are updated to reflect the change.
+ """
+ self.interp.call( 'mapinfo', self.name, 'delete' )
+
+
+ def duplicate( self, *args ):
+ """
+ B{Optional}
+ @type name: Name of the new mapinfo
+ @param name: Must be use carrefully !!
+ Create a new mapinfo that is a exact copy of this mapinfo Object.
+ """
+ classe = Mapinfo
+ obj = new.instance( classe )
+ if len( args ):
+ new_name = args[0]
+ else:
+ new_name = str( obj )
+ self.interp.call( 'mapinfo', self.name, 'duplicate', new_name )
+ return obj
+
+ def add_text( self, text_style, line_style, x, y, text ):
+ """
+ Add a new graphical element to the mapinfo object text.
+ This element describes a line of text.
+ @type text_style: {normal|underlined}
+ @param text_style: text style
+ @type line_style: string
+ @param line_style: a line style (simple, dashed, dotted, mixed, marked) to be used for the underline
+ @type X: int
+ @param X: Coord on X axe
+ @type Y: int
+ @param Y: Coord on Y axe
+ @type text: string
+ @param : a string describing the text.
+
+ """
+ self.interp.call( 'mapinfo', self.name, 'add', 'text', text_style,
+ line_style, x, y, text )
+
+ def add_line( self, line_style, width, x1, y1, x2, y2 ):
+ """
+ Add a new graphical element to the mapinfo object line.
+ This element describes a line segment.
+ @type line_style: {simple|dashed|dotted|mixed|marked}
+ @param line_style: a line style
+ @type width: int
+ @param width: the line width in pixels
+ @type x1: int
+ @param x1: coords on X axe
+ @type x2: int
+ @param x2: coords on Y axe
+ @type x3: int
+ @param x3: end vertices on X axe
+ @type x4: int
+ @param x4: end vertices on Y axe
+ four integer values setting the X and Y coordinates of the two end vertices.
+ """
+ self.interp.call( 'mapinfo', self.name, 'add', 'line', line_style,
+ width, x1, y1, x2, y2 )
+
+ def add_arc( self, line_style, width, cx, cy, radius, start, extent ):
+ """
+ Add a new graphical element to the mapinfo object arc.
+
+ @type line_style: {simple|dashed|dotted|mixed|marked}
+ @param line_style: a line style
+ @type width: int
+ @param width: the line width in pixels
+ @type cx: int
+ @param cx: X of arc center
+ @type cy: int
+ @param cy: Y of arc center
+ @type radius: int
+ @param radius: the arc radius
+ @type start: int
+ @param start: the start angle (in degree)
+ @type extent: int
+ @param extent: the angular extent of the arc (in degree).
+
+ """
+ self.interp.call( 'mapinfo', self.name, 'add', 'arc', line_style,
+ width, cx, cy, radius, start, extent )
+
+ def add_symbol( self, x, y, index ):
+ """
+ Add a new graphical element to the mapinfo object symbol.
+ @type x: int
+ @param x: position on X
+ @type y: int
+ @param y: position on Y
+
+ @type index: int
+ @param : an integer setting the symbol index in the -symbols list of the map item
+
+ """
+ self.interp.call( 'mapinfo', self.name, 'add', 'symbol', x, y, index )
+
+ def count( self, type ):
+ """
+ @type type: {text|arc|line|symbol}
+ @param type:
+ Return an integer value that is the number of elements matching type in the mapinfo.
+ type may be one the legal element types
+ """
+ return self.interp.call( 'mapinfo', self.name, 'count', type )
+
+ def get( self, type, index ):
+ """
+ Return the parameters of the element at index with type type in the mapinfo.
+ The returned value is a list.
+ The exact number of parameters in the list and their meaning depend on type and is accurately described in mapinfo add.
+ type may be one the legal element types as described in the mapinfo add command.
+ Indices are zero based and elements are listed by type.
+ """
+ return self.interp.call( 'mapinfo', self.name, 'remove', type, index )
+
+ def replace( self, type, index, *args ):
+ """
+ Replace all parameters for the element at index with type type in the mapinfo.
+ The exact number and content for args depend on type and is accurately described in mapinfo add.
+ type may be one the legal element types as described in the mapinfo add command.
+ Indices are zero based and elements are listed by type.
+ """
+ return self.interp.call( 'mapinfo', self.name, 'replace',
+ type, index, args )
+
+ def remove( self, type, index ):
+ """
+ Remove the element at index with type type in the mapinfo.
+ type may be one the legal element types as described in the mapinfo add command. Indices are zero based and elements are listed by type.
+ """
+ return self.interp.call( 'mapinfo', self.name, 'remove', type, index )
+
+ def scale( self, factor ):
+ """
+ """
+ self.interp.call( 'mapinfo', self.name, 'scale', factor )
+
+ def translate( self, xAmount, yAmount ):
+ """
+ """
+ self.interp.call( 'mapinfo', self.name, 'translate', xAmount, yAmount )
+
+class Videomap ( Mapinfo ):
+ """
+ create a mapinfo from a proprietary
+ file format for simple maps, in use in french Air Traffic Control Centres. The format is the
+ binary cautra4 (with x and y in 1/8nm units)
+ """
+ def __init__( self, tk, *args ):
+ """
+ @type filename:
+ @param filename:
+ @type mapinfoname:
+ @param mapinfoname:
+ Load the videomap sub-map located at position index in the file named fileName into a mapinfo object named mapInfoName. It is possible, if needed, to use the videomap ids command to help translate a sub-map id into a sub-map file index.
+ """
+ self.tk = tk.tk
+ args = args + ( self, )
+ self.tk.call( 'videomap', 'load', *args )
+
+
+ def ids( self, filename ):
+ """
+ @type filename: string
+ @param filename: filename where to search syb-map
+ B{Class Method}
+ Return all sub-map ids that are described in the videomap file described by fileName.
+ The ids are listed in file order. This command makes possible to iterate through a videomap file
+ one sub-map at a time, to know how much sub-maps are there and to sort them according to their ids.
+ """
+ return self.tk.call( 'videomap', 'ids', filename )
+
+class Colors:
+ """
+ Classe abstraite utilitaire permettant de gérer sous forme d'objet
+ les couleurs aux formats Zinc
+ """
+ def __init__( self ):
+ self.lColors = []
+
+ #TODO:
+ def getColorsIter( self ):
+ """
+ Renvoie un itérateur sur les couleurs
+ """
+ return self.lColors.__iter__()
+
+ def addColor( self, color, alpha = 100,
+ colorposition = 0, mid_span_position = 50 ):
+ self.lColors.append( ( color, alpha, colorposition, mid_span_position ) )
+
+ def __repr__( self ):
+ res = ""
+ for i in self.lColors:
+ res = "%s%s;%s %s %s|" % ( res, i[0], i[1], i[2], i[3] )
+ return res[:-1]
+
+class AxialGradientColor( Colors ):
+ def __init__( self, *params ):
+ """
+ params : degre or x1, y1, x2, y2 which define angle and extension of the axe
+ =axial degre | gradient_step1 | ... | gradient_stepn or
+ =axial x1 y1 x2 y2 | gradient_step1 | ... | gradient_stepn
+ """
+ Colors.__init__( self )
+ count = 0
+ self.params = ""
+ for i in params:
+ self.params = "%s %s" % ( self.params, str( i ) )
+ count += 1
+ if ( count != 1 ) and ( count != 4 ):
+ raise Exception( "Bad Format of params %s" % count )
+
+ def __repr__( self ):
+ res = "=axial %s" % self.params
+ if not ( len( self.lColors ) ):
+ raise Exception( "Bad Format, must have one color less" )
+ res = "%s | %s" % ( res, Colors.__repr__( self ) )
+ return res
+
+class RadialGradientColor( Colors ):
+ def __init__( self, *params ):
+ """
+ =radial x y | gradient_step1 | ... | gradient_stepn or
+ =radial x1 y1 x2 y2 | gradient_step1 | ... | gradient_stepn
+ The x y parameters define the center of the radial.
+ The x1 y1 x2 y2 parameters define both the center and the extension of the radial.
+ """
+ Colors.__init__( self )
+ count = 0
+ self.params = ""
+ for i in params:
+ self.params = "%s %s" % ( self.params, str( i ) )
+ count += 1
+ if ( ( count!= 2 ) and ( count != 4 ) ):
+ raise Exception( "Bad Format of params %s"%count )
+
+ def __repr__( self ):
+ res = "=radial %s " % self.params
+ if not ( len( self.lColors ) ):
+ raise Exception( "Bad Format, must have one color less" )
+ res = "%s | %s" % ( res, Colors.__repr__( self ) )
+ return res
+
+class PathGradientColor( Colors ):
+ def __init__( self, *params ):
+ """
+ =path x y | gradient_step1 | ... | gradient_stepn
+ The x y parameters define the center of the gradient.
+ """
+ Colors.__init__( self )
+ count = 0
+ self.params = ""
+ for i in params:
+ self.params = "%s %s" % ( self.params, str( i ) )
+ count += 1
+ if ( count != 2 ):
+ raise Exception( "Bad Format of params %s" % count )
+
+ def __repr__( self ):
+ res = "=path %s " % self.params
+ if not ( len( self.lColors ) ):
+ raise Exception( "Bad Format, must have one color less" )
+ res = "%s | %s" % ( res, Colors.__repr__( self ) )
+ return res
+
+class ConicalGradientColor( Colors ):
+ def __init__( self, *params ):
+ """
+ =conical degre | gradient_step1 | ... | gradient_stepn or
+ =conical degre x y | gradient_step1 | ... | gradient_stepn or
+ =conical x1 y1 x2 y2 | gradient_step1 | ... | gradient_stepn
+
+ The degre parameter defines the angle of the cone in the usual trigonometric sense.
+ The optional x y parameters define the center of the cone.
+ By default, it is the center of the bounding-box.
+ The x1 y1 x2 y2 parameters define the center and the angle of the cone.
+
+ All x and y coordinates are expressed in percentage of the bounding box,
+ relatively to the center of the bounding box.
+ So 0 0 means the center while -50 -50 means the lower left corner of the bounding box.
+
+ If none of the above gradient type specification is given,
+ the gradient will be drawn as an axial gradient with a null angle.
+ """
+ Colors.__init__( self )
+ count = 0
+ self.params = ""
+ for i in params:
+ self.params = "%s %s" % ( self.params, str( i ) )
+ count += 1
+ if ( count != 1 ) and ( count != 3 ) and ( count != 4 ):
+ raise Exception( "Bad Format of params %s" % count )
+
+ def __repr__( self ):
+ res = "=conical %s " % self.params
+ if not ( len( self.lColors ) ):
+ raise Exception( "Bad Format, must have one color less" )
+ res = "%s | %s" % ( res, Colors.__repr__( self ) )
+ return res
+
+
+# ---- self-test ----------------------------------------------------------
+if __name__ == '__main__':
+ from Tkinter import *
+ import Zinc
+ def createItem( zinc, group, ev ):
+ print >> sys.stdout, "CreateIHM"
+ sys.stdout.flush()
+ Zinc.Rectangle( zinc, group,
+ ( 100, 100, 150, 150 ),
+ linewidth = "10", linecolor = '#FFFF00',
+ relief = "roundgroove", filled = 1,
+ fillcolor = "red", tags = ( "hello", "test" ) )
+ sys.stdout.write( "hello_clic" + str( ev ) )
+
+ z = Zinc.Zinc( master = None, render = 1, height = 200, width = 400 )
+ g1 = Zinc.Group( z, 1 )
+ r = Zinc.Rectangle( z, g1, ( 0, 0, 400, 200 ),
+ linewidth = "10",
+ linecolor = '#FFFF00',
+ relief = "roundgroove",
+ filled = 1,
+ fillcolor = "#FFFFFF",
+ tags = ( "hello", "test" ) )
+ t = Zinc.Text( z, g1, position = ( 40, 100 ), text = z.version )
+# z.bind_tag("hello","<1>",lambda ev,z=z,g=g1 : createItem(z,g,ev))
+ z.configure( backcolor = 'black' )
+ z.pack()
+ z.mainloop()
+
+# Zinc.py ends here
+
diff --git a/Python/build/lib.linux-x86_64-2.7/Zinc/__init__.py b/Python/build/lib.linux-x86_64-2.7/Zinc/__init__.py
new file mode 100755
index 0000000..d8e4f37
--- /dev/null
+++ b/Python/build/lib.linux-x86_64-2.7/Zinc/__init__.py
@@ -0,0 +1,4 @@
+from Zinc import *
+import graphics
+import geometry
+import pictorial
diff --git a/Python/build/lib.linux-x86_64-2.7/Zinc/geometry.py b/Python/build/lib.linux-x86_64-2.7/Zinc/geometry.py
new file mode 100755
index 0000000..4063b61
--- /dev/null
+++ b/Python/build/lib.linux-x86_64-2.7/Zinc/geometry.py
@@ -0,0 +1,410 @@
+# -*- coding: iso-8859-1 -*-
+"""
+# Geometrical basic Functions :
+# -----------------------------
+# perpendicular_point
+# line_angle
+# linenormal
+# vertex_angle
+# arc_pts
+# rad_point
+# bezier_compute
+# bezier_segment
+# bezier_point
+"""
+
+from math import pi, radians, atan2, sin, cos
+
+# limite globale d'approximation courbe bezier
+bezierClosenessThreshold = .2
+def perpendicular_point (point, line):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::perpendicular_point
+ # retourne les coordonnées du point perpendiculaire abaissé d'un point
+ # sur une ligne
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # point : <coords> coordonnées du point de référence
+ # line : <coordsList> coordonnées des 2 points de la ligne de référence
+ #---------------------------------------------------------------------------
+ """
+ (p1, p2) = line
+
+ # cas partiuculier de lignes ortho.
+ min_dist = .01
+ if (abs(p2[1] - p1[1]) < min_dist) :
+ # la ligne de référence est horizontale
+ return (point[0], p1[1])
+
+ elif (abs(p2[0] - p1[0]) < min_dist) :
+ # la ligne de référence est verticale
+ return (p1[0], point[1])
+
+ a1 = float(p2[1] - p1[1]) / float(p2[0] - p1[0])
+ b1 = p1[1] - (a1 * p1[0])
+
+ a2 = -1.0 / a1
+ b2 = point[1] - (a2 * point[0])
+
+ x = (b2 - b1) / (a1 - a2)
+ y = (a1 * x) + b1
+
+ return (x, y)
+
+def line_angle(startpoint, endpoint):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::line_angle
+ # retourne l'angle d'un point par rapport à un centre de référence
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # startpoint : <coords> coordonnées du point de départ du segment
+ # endpoint : <coords> coordonnées du point d'extremité du segment
+ #---------------------------------------------------------------------------
+ """
+ angle = atan2(endpoint[1] - startpoint[1], endpoint[0] - startpoint[0])
+
+ angle += pi/2
+ angle *= float(180)/pi
+ if (angle < 0):
+ angle += 360
+
+ return angle
+
+def linenormal(startpoint, endpoint):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::linenormal
+ # retourne la valeur d'angle perpendiculaire à une ligne
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # startpoint : <coords> coordonnées du point de départ du segment
+ # endpoint : <coords> coordonnées du point d'extremité du segment
+ #---------------------------------------------------------------------------
+ """
+ angle = line_angle(startpoint, endpoint) + 90
+
+ if (angle > 360):
+ angle -= 360
+ return angle
+
+def vertex_angle(pt0, pt1, pt2):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::vertex_angle
+ # retourne la valeur de l'angle formée par 3 points
+ # ainsi que l'angle de la bisectrice
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # pt0 : <coords> coordonnées du premier point de définition de l'angle
+ # pt1 : <coords> coordonnées du deuxième point de définition de l'angle
+ # pt2 : <coords> coordonnées du troisième point de définition de l'angle
+ #---------------------------------------------------------------------------
+ """
+ angle1 = line_angle(pt0, pt1)
+ angle2 = line_angle(pt2, pt1)
+
+ if angle2 < angle1 :
+ angle2 += 360
+ alpha = angle2 - angle1
+ bisectrice = angle1 + (float(alpha)/2)
+
+ return (alpha, bisectrice)
+
+
+def arc_pts(center, radius, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::arc_pts
+ # calcul des points constitutif d'un arc
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # center : <coordonnées> centre de l'arc,
+ # radius : <dimension> rayon de l'arc,
+ # options :
+ # -angle : <angle> angle de départ en degré de l'arc (par défaut 0)
+ # -extent : <angle> delta angulaire en degré de l'arc (par défaut 360),
+ # -step : <dimension> pas de progresion en degré (par défaut 10)
+ #---------------------------------------------------------------------------
+ """
+ if center is None :
+ center = [0, 0]
+ if (options.has_key('angle')) :
+ angle = options['angle']
+ else:
+ angle = 0
+ if (options.has_key('extent')) :
+ extent = options['extent']
+ else:
+ extent = 360
+ if (options.has_key('step')) :
+ step = options['step']
+ else:
+ step = 10
+ pts = []
+
+ if (extent > 0 and step > 0) :
+ #A Verifier !
+ alpha = angle
+ while(alpha <= angle+extent):
+ (x_n, y_n) = rad_point(center, radius, alpha)
+ pts.append((x_n, y_n))
+ angle += step
+
+ elif (extent < 0 and step < 0) :
+ #Ca me semble buggue !!
+ #Si extent négatif, il faut aussi que step le soit
+ #Si ca boucle !
+ alpha = angle
+ while(alpha >= angle+extent):
+ pts.append(rad_point(center, radius, alpha))
+ alpha += step
+ else:
+ raise ValueError("Step and Extent havent the same sign")
+ return tuple(pts)
+
+def rad_point(center, radius, angle):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::rad_point
+ # retourne le point circulaire défini par centre-rayon-angle
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # center : <coordonnée> coordonnée [x,y] du centre de l'arc,
+ # radius : <dimension> rayon de l'arc,
+ # angle : <angle> angle du point de circonférence avec le centre du cercle
+ #---------------------------------------------------------------------------
+ """
+ alpha = radians(angle)
+
+ xpt = center[0] + (radius * cos(alpha))
+ ypt = center[1] + (radius * sin(alpha))
+
+ return (xpt, ypt)
+
+def bezier_segment(coords, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::bezier_segment
+ # Calcul d'une approximation de segment (Quadratique ou Cubique) de bezier
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # points : <[P1, C1, <C1>, P2]> liste des points définissant
+ # le segment de bezier
+ #
+ # options :
+ # -tunits : <integer> nombre pas de division des segments bezier
+ # (par défaut 20)
+ # -skipend : <boolean> : ne pas retourner le dernier point du
+ # segment (chainage)
+ #---------------------------------------------------------------------------
+ """
+ if (options.has_key('tunits')) :
+ tunits = options['tunits']
+ else:
+ tunits = 20
+
+
+ if options.has_key('skipend'):
+ skipendpt = options['skipend']
+ else:
+ skipendpt = None
+
+ pts = []
+
+ if (skipendpt) :
+ lastpt = tunits-1
+ else:
+ lastpt = tunits
+ for i in xrange(0, lastpt+1):
+ if (i) :
+ t = (i/tunits)
+ else:
+ t = i
+ pts.append(bezier_point(t, coords))
+
+ return pts
+
+
+def bezier_point(t, coords):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::bezier_point
+ # calcul d'un point du segment (Quadratique ou Cubique) de bezier
+ # params :
+ # t = <n> (représentation du temps : de 0 à 1)
+ # coords = (P1, C1, <C1>, P2) liste des points définissant le segment
+ # de bezier P1 et P2 : extémités du segment et pts situés sur la courbe
+ # C1 <C2> : point(s) de contrôle du segment
+ #---------------------------------------------------------------------------
+ # courbe bezier niveau 2 sur (P1, P2, P3)
+ # P(t) = (1-t)²P1 + 2t(1-t)P2 + t²P3
+ #
+ # courbe bezier niveau 3 sur (P1, P2, P3, P4)
+ # P(t) = (1-t)³P1 + 3t(1-t)²P2 + 3t²(1-t)P3 + t³P4
+ #---------------------------------------------------------------------------
+ """
+ ncoords = len(coords)
+ if ncoords == 3:
+ (p1, c1, p2) = coords
+ c2 = None
+ elif ncoords == 4:
+ (p1, c1, c2, p2) = coords
+
+ # extrémités : points sur la courbe
+ #A VERIFIER
+ #Pas compris
+ if (not t):
+ return tuple(p1)
+ if (t >= 1.0):
+ return p2
+
+
+ t2 = t * t
+ t3 = t2 * t
+ pt = []
+
+ # calcul pour x et y
+ for i in (0, 1) :
+
+ if (c2) :
+ r1 = (1 - (3*t) + (3*t2) - t3) * p1[i]
+ r2 = ((3*t) - (6*t2) + (3*t3)) * c1[i]
+ r3 = ((3*t2) - (3*t3)) * c2[i]
+ r4 = (t3) * p2[i]
+
+ pt[i] = (r1 + r2 + r3 + r4)
+
+ else :
+ r1 = (1 - (2*t) + t2) * p1[i]
+ r2 = ((2*t) - (2*t2)) * c1[i]
+ r3 = (t2) * p2[i]
+
+ pt[i] = (r1 + r2 + r3)
+
+ return tuple(pt)
+
+def bezier_compute(coords, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::bezier_compute
+ # Retourne une liste de coordonnées décrivant un segment de bezier
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : <coordsList> liste des points définissant le segment
+ # de bezier
+ #
+ # options :
+ # -precision : <dimension> seuil limite du calcul d'approche de la courbe
+ # -skipend : <boolean> : ne pas retourner le dernier point du segment
+ # (chaînage bezier)
+ #---------------------------------------------------------------------------
+ """
+ if (options.has_key('precision')) :
+ precision = options['precision']
+ else:
+ precision = bezierClosenessThreshold
+ lastit = []
+
+ subdivide_bezier(coords, lastit, precision)
+
+ if (not options.has_key('skipend') or not options['skipend']):
+ lastit.append(coords[3])
+
+ return lastit
+
+def smallenough_bezier(bezier, precision):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::smallEnought
+ # intégration code Stéphane Conversy : calcul points bezier
+ # (précision auto ajustée)
+ #---------------------------------------------------------------------------
+ # distance is something like num/den with den=sqrt(something)
+ # what we want is to test that distance is smaller than precision,
+ # so we have distance < precision ? eq. to distance^2 < precision^2 ?
+ # eq. to (num^2/something) < precision^2 ?
+ # eq. to num^2 < precision^2*something
+ # be careful with huge values though (hence 'long long')
+ # with common values: 9add 9mul
+ #---------------------------------------------------------------------------
+ """
+ (pt_x, pt_y) = (0, 1)
+ (a, b) = (bezier[0], bezier[3])
+
+ den = ((a[pt_y]-b[pt_y])*(a[pt_y]-b[pt_y])) + ((b[pt_x]-a[pt_x])*(b[pt_x]-a[pt_x]))
+ p = precision*precision
+
+ # compute distance between P1|P2 and P0|P3
+ mat = bezier[1]
+ num1 = ((mat[pt_x]-a[pt_x])*(a[pt_y]-b[pt_y])) + ((mat[pt_y]-a[pt_y])*(b[pt_x]-a[pt_x]))
+
+ mat = bezier[2]
+ num2 = ((mat[pt_x]-a[pt_x])*(a[pt_y]-b[pt_y])) + ((mat[pt_y]-a[pt_y])*(b[pt_x]-a[pt_x]))
+
+ # take the max
+ num1 = max(num1, num2)
+
+ if (p*den > (num1*num1)):
+ return 1
+ else:
+ return 0
+
+def subdivide_bezier(bezier, it, precision, integeropt):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::subdivide_bezier
+ # subdivision d'une courbe de bezier
+ #---------------------------------------------------------------------------
+ """
+ (b0, b1, b2, b3) = bezier
+
+ if (smallenough_bezier(bezier, precision)) :
+ it.append((b0[0], b0[1]))
+
+ else :
+ (left, right) = (None, None)
+
+ for i in (0, 1) :
+
+ if (integeropt) :
+ # int optimized (6+3=9)add + (5+3=8)shift
+
+ left[0][i] = b0[i]
+ left[1][i] = (b0[i] + b1[i]) >> 1
+ # keep precision
+ left[2][i] = (b0[i] + b2[i] + (b1[i] << 1)) >> 2
+
+ tmp = (b1[i] + b2[i])
+ left[3][i] = (b0[i] + b3[i] + (tmp << 1) + tmp) >> 3
+
+ right[3][i] = b3[i]
+ right[2][i] = (b3[i] + b2[i]) >> 1
+ # keep precision
+ right[1][i] = (b3[i] + b1[i] + (b2[i] << 1) ) >> 2
+ right[0][i] = left[3][i]
+
+ else :
+ # float
+
+ left[0][i] = b0[i]
+ left[1][i] = float(b0[i] + b1[i]) / 2
+ left[2][i] = float(b0[i] + (2*b1[i]) + b2[i]) / 4
+ left[3][i] = float(b0[i] + (3*b1[i]) + (3*b2[i]) + b3[i]) / 8
+
+ right[3][i] = b3[i]
+ right[2][i] = float(b3[i] + b2[i]) / 2
+ right[1][i] = float(b3[i] + (2*b2[i]) + b1[i]) / 4
+ right[0][i] = float(b3[i] + (3*b2[i]) + (3*b1[i]) + b0[i]) / 8
+
+
+
+ subdivide_bezier(left, it, precision, integeropt)
+ subdivide_bezier(right, it, precision, integeropt)
+
+
+#Local Variables:
+#mode : python
+#tab-width: 4
+#end:
diff --git a/Python/build/lib.linux-x86_64-2.7/Zinc/graphics.py b/Python/build/lib.linux-x86_64-2.7/Zinc/graphics.py
new file mode 100755
index 0000000..5277e5c
--- /dev/null
+++ b/Python/build/lib.linux-x86_64-2.7/Zinc/graphics.py
@@ -0,0 +1,2351 @@
+# -*- coding: iso-8859-1 -*-
+"""
+#-------------------------------------------------------------------------------
+#
+# Graphics.py
+# some graphic design functions
+#
+#-------------------------------------------------------------------------------
+# Functions to create complexe graphic component :
+# ------------------------------------------------
+# build_zinc_item (realize a zinc item from description hash table
+# management of enhanced graphics functions)
+#
+# repeat_zinc_item (duplication of given zinc item)
+#
+# Function to compute complexe geometrical forms :
+# (text header of functions explain options for each form,
+# function return curve coords using control points of cubic curve)
+# -----------------------------------------------------------------
+# rounded_rectangle_coords (return curve coords of rounded rectangle)
+# hippodrome_coords (return curve coords of circus form)
+# ellipse_coords (return curve coords of ellipse form)
+# polygon_coords (return curve coords of regular polygon)
+# roundedcurve_coords (return curve coords of rounded curve)
+# polyline_coords (return curve coords of polyline)
+# shiftpath_coords (return curve coords of shifting path)
+# tabbox_coords (return curve coords of tabbox's pages)
+# pathline_coords (return triangles coords of pathline)
+#
+# Function to compute 2D 1/2 relief and shadow :
+# function build zinc items (triangles and curve) to simulate this
+# -----------------------------------------------------------------
+# graphicitem_relief (return triangle items simulate relief of given item)
+# polyline_relief_params (return triangle coords
+# and lighting triangles color list)
+# graphicitem_shadow (return triangles and curve items
+# simulate shadow of given item))
+# polyline_shadow_params (return triangle and curve coords
+# and shadow triangles color list))
+#
+#
+#-------------------------------------------------------------------------------
+# Authors: Jean-Luc Vinot <vinot@cena.fr>
+# PM2PY: Guillaume Vidon <vidon@ath.cena.fr>
+#
+# $Id: graphics.py 1697 2005-06-13 00:25:58Z vidon $
+#-------------------------------------------------------------------------------
+"""
+VERSION = "1.0"
+__revision__ = "0.1"
+
+import logging
+import types
+import re
+from geometry import *
+from pictorial import *
+from math import pi, radians, atan2, sqrt, sin, cos
+
+graphiclogger = logging.getLogger('Graphics')
+debug = graphiclogger.debug
+error = graphiclogger.error
+exception = graphiclogger.exception
+log = lambda msg : graphiclogger.log(logging.DEBUG, msg)
+
+# constante facteur point directeur (conique -> quadratique)
+const_ptd_factor = .5523
+
+def transdic(**dict):
+ newdic={}
+ for key, val in dict.items():
+ if (type(val) is types.ListType):
+ newdic[key] = tuple(val)
+ else:
+ newdic[key] = val
+ return newdic
+
+def is_flat_list(apts):
+ if reduce(lambda x, y : x and (type(y) in ( types.FloatType, types.IntType)),
+ apts):
+ if len(apts) % 2:
+ raise ValueError("Not a valid Coords list")
+ else :
+ return True
+ else :
+ return False
+
+def is_point(apoint):
+ if (type(apoint) in ( types.TupleType, types.ListType)):
+ if len(apoint) == 2 :
+ if reduce(lambda x, y : x and (type(y) in ( types.FloatType, types.IntType)),
+ apts):
+ return True
+ else :
+ return False
+ elif reduce(lambda x, y : x and (type(y) in ( types.FloatType, types.IntType)),
+ apts[:-1])\
+ and type(apts[-1]) in ('c', 'n'):
+ return True
+ else :
+ return False
+ else :
+ return False
+
+# def is_tuple_list(apts):
+# if reduce(lambda x, y : x \
+# and is_point(x)),
+# apts):
+
+
+def lpts2coords(lpts):
+ coords = []
+ if (type(lpts) in ( types.TupleType, types.ListType )):
+ for point in lpts :
+ coords.append(tuple(point))
+ return tuple(coords)
+
+def coords2lpts(coords):
+ lpts = []
+ if (type(coords) in ( types.TupleType, types.ListType )):
+ for point in coords :
+ lpts.append(list(point))
+ else :
+ raise ValueError("Invalid Coords %s "%coords)
+ return lpts
+
+def build_zinc_item(widget, pgroup = 1, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::build_zinc_item
+ # Création d'un objet Zinc de représentation
+ #---------------------------------------------------------------------------
+ # types d'items valides :
+ # les items natifs zinc : group, rectangle, arc, curve, text, icon
+ # les items ci-après permettent de spécifier des curves 'particulières' :
+ # -roundedrectangle : rectangle à coin arrondi
+ # -hippodrome : hippodrome
+ # -ellipse : ellipse un centre 2 rayons
+ # -polygone : polygone régulier à n cotés (convexe ou en étoile)
+ # -roundedcurve : curve multicontours à coins arrondis (rayon unique)
+ # -polyline : curve multicontours à coins arrondis (le rayon pouvant
+ # être défini
+ # spécifiquement pour chaque sommet)
+ # -pathline : création d'une ligne 'épaisse' avec l'item Zinc
+ # triangles décalage par rapport à un chemin donné
+ # (largeur et sens de décalage)
+ # dégradé de couleurs de la ligne (linéaire, transversal
+ # ou double)
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant du widget Zinc
+ # parentgroup : <tagOrId> identifiant du group parent
+ #
+ # options :
+ # -itemtype : type de l'item à construire (type zinc ou metatype)
+ # -coords : <coords|coordsList> coordonnées de l'item
+ # -metacoords : <hastable> calcul de coordonnées par type
+ # d'item différent de itemtype
+ # -contours : <contourList> paramètres multi-contours
+ # -params : <hastable> arguments spécifiques de l'item à passer
+ # au widget
+ # -addtags : [list of specific tags] to add to params -tags
+ # -texture : <imagefile> ajout d'une texture à l'item
+ # -pattern : <imagefile> ajout d'un pattern à l'item
+ # -relief : <hastable> création d'un relief à l'item invoque la fonction
+ # graphicitem_relief()
+ # -shadow : <hastable> création d'une ombre portée à l'item invoque
+ # la fonction graphicitem_shadow()
+ # -scale : <scale_factor|[xscale_factor,yscale_factor]> application
+ # d'une transformation zinc->scale à l'item
+ # -translate : <[delta_x,delta_y]> application d'un transformation zinc->translate
+ # à l'item.
+ # -rotate : <angle> application d'une transformation zinc->rotate
+ # (en degré) à l'item
+ # -name : <str> nom de l'item
+ # spécifiques item group :
+ # -clip : <coordList|hashtable> paramètres de clipping d'un item group
+ # (coords ou item)
+ # -items : <hashtable> appel récursif de la fonction permettant
+ # d'inclure des items au groupe
+ #---------------------------------------------------------------------------
+ #
+ #---------------------------------------------------------------------------
+ """
+
+ if options.has_key('parentgroup'):
+ parentgroup = options['parentgroup']
+ else :
+ parentgroup = pgroup
+ try:
+ itemtype = options['itemtype']
+ except KeyError:
+ raise ValueError("Must have itemtype option")
+ try:
+ coords = options['coords']
+ except KeyError:
+ try:
+ coords = options['metacoords']
+ except KeyError :
+ raise ValueError("Must have coords or metacoords option")
+
+ if options.has_key('params'):
+ params = options['params']
+ else:
+ params = {}
+
+ #return unless($widget and $itemtype
+ #and ($coords or $options{'-metacoords'}))
+
+ try:
+ name = options['name']
+ except KeyError:
+ name = None
+
+ item = None
+ metatype = None
+ items = []
+ reliefs = []
+ shadows = []
+ tags = []
+
+ #--------------------
+ # GEOMETRIE DES ITEMS
+
+ # gestion des types d'items particuliers et à raccords circulaires
+ if (itemtype in ( 'roundedrectangle',
+ 'hippodrome',
+ 'polygone',
+ 'ellipse',
+ 'roundedcurve',
+ 'polyline',
+ 'curveline')):
+
+ # par défaut la curve sera fermée -closed = 1
+ if not params.has_key('closed'):
+ params['closed'] = 1
+ metatype = itemtype
+ itemtype = 'curve'
+
+ # possibilité de définir les coordonnées initiales par metatype
+ if (options.has_key('metacoords')) :
+ options['coords'] = meta_coords( **options['metacoords'])
+
+ # création d'une pathline à partir d'item zinc triangles
+ elif (itemtype == 'pathline') :
+ itemtype = 'triangles'
+ if (options.has_key('metacoords')) :
+ coords = meta_coords( **options['metacoords'])
+
+ if (options.has_key('graduate')) :
+ numcolors = len(coords)
+ lcolors = path_graduate(widget,
+ numcolors,
+ options['graduate'])
+ params['colors'] = tuple(lcolors)
+
+ if options.has_key('coords'):
+ coords = pathline_coords(**options)
+ else:
+ coords = pathline_coords(coords, **options)
+
+ # création d'une boite à onglet
+ elif (itemtype == 'tabbox') :
+ return build_tabboxitem(widget, parentgroup, **options)
+
+ # calcul des coordonnées finales de la curve
+ if (metatype is not None):
+ coords = meta_coords(type = metatype, **options)
+
+
+ # gestion du multi-contours (accessible pour tous les types
+ # d'items géometriques)
+ if (options.has_key('contours') and (metatype is not None)) :
+ lcontours = options['contours']
+ contours=[]
+ numcontours = len(contours)
+ for contour in lcontours:
+ # radius et corners peuvent être défini
+ # spécifiquement pour chaque contour
+ (atype, way, addcoords,) = contour[:3]
+ if len(contour) >= 4:
+ radius = contour[3]
+ else :
+ radius = None
+ if len(contour) >= 5:
+ corners = contour[4]
+ else:
+ corners = None
+ if len(contour) >= 6:
+ corners_radius = contour[5]
+ else :
+ corners_radius = None
+ if (radius is None):
+ if options.has_key('radius'):
+ radius = options['radius']
+ else :
+ raise ValueError("radius option requiered")
+
+ newcoords = meta_coords(type = metatype,
+ coords = addcoords,
+ radius = radius,
+ corners = corners,
+ corners_radius = corners_radius
+ )
+ contours.append((atype, way, newcoords))
+
+ options['contours'] = contours
+
+ #----------------------
+ # REALISATION DES ITEMS
+
+ # ITEM GROUP
+ # gestion des coordonnées et du clipping
+ if (itemtype == 'group') :
+ item = widget.add(itemtype,
+ parentgroup,
+ **params)
+ widget.addtag_withtag(name, item)
+ if coords:
+ widget.coords(item, tuple(coords))
+
+ # clipping du groupe par item ou par géometrie
+ if (options.has_key('clip')) :
+ clipbuilder = options['clip']
+ clip = None
+
+ # création d'un item de clipping
+ if (type(clipbuilder) is types.DictType
+ and clipbuilder.has_key('itemtype')):
+ clip = build_zinc_item(widget, item, **clipbuilder)
+
+ elif (type(clipbuilder) in (types.TupleType, types.ListType)
+ or widget.type(clipbuilder)) :
+ clip = clipbuilder
+
+ if (clip):
+ widget.itemconfigure(item, clip = clip)
+
+ # créations si besoin des items contenus dans le groupe
+ if (options.has_key('items')
+ and type(options['items']) is types.DictType) :
+ for (itemname, itemstyle) in options['items'].items() :
+ if not itemstyle.has_key('name'):
+ itemstyle['name'] = itemname
+ build_zinc_item(widget, item, **itemstyle)
+
+
+ # ITEM TEXT ou ICON
+ elif (itemtype in ('text', 'icon')) :
+ imagefile = None
+ if (itemtype == 'icon') :
+ imagefile = params['image']
+ image = get_image(widget, imagefile)
+ if (image) :
+ params['image'] = image
+ else:
+ params['image'] = ""
+
+
+ item = widget.add(itemtype,
+ parentgroup,
+ position = coords,
+ **params
+ )
+ if imagefile:
+ params['image'] = imagefile
+
+
+ # ITEMS GEOMETRIQUES -> CURVE
+ else :
+ nparams=params
+ item = widget.add(itemtype,
+ parentgroup,
+ lpts2coords(coords),
+ **params
+ )
+
+ if (itemtype == 'curve' and options.has_key('contours')) :
+ for contour in options['contours'] :
+ contour = list(contour)
+ contour[2] = tuple(contour[2])
+ widget.contour(item, *contour)
+
+ # gestion du mode norender
+ if (options.has_key('texture')) :
+ texture = get_texture(widget, options['texture'])
+ if texture:
+ widget.itemconfigure(item, tile = texture)
+
+ if (options.has_key('pattern')) :
+ bitmap = get_pattern(**options['pattern'])
+ if bitmap:
+ widget.itemconfigure(item, fillpattern = bitmap)
+
+ # gestion des tags spécifiques
+ if (options.has_key('addtags')) :
+ tags = options['addtags']
+
+ params_tags = params['tags']
+ if params_tags:
+ tags.extend(params_tags)
+
+ widget.itemconfigure(item, tags = tags)
+
+ #-------------------------------
+ # TRANSFORMATIONS ZINC DE L'ITEM
+
+ # transformation scale de l'item si nécessaire
+ if (options.has_key('scale')) :
+ scale = options['scale']
+ if (type(scale) is not types.TupleType) :
+ scale = (scale, scale)
+ widget.scale(item, scale)
+
+
+ # transformation rotate de l'item si nécessaire
+ if (options.has_key('rotate')):
+ widget.rotate(item, radians(options['rotate']))
+
+ # transformation translate de l'item si nécessaire
+ if (options.has_key('translate')):
+ widget.translate(item, options['translate'])
+
+
+ # répétition de l'item
+ if (options.has_key('repeat')) :
+ items.extend((item,
+ repeat_zinc_item(widget, item, **options['repeat'])))
+
+ #-----------------------
+ # RELIEF ET OMBRE PORTEE
+
+ # gestion du relief
+ if (options.has_key('relief')) :
+ if (len(items)) :
+ target = items
+ else:
+ target = item
+ reliefs.extend(graphicitem_relief(widget,
+ target, **options['relief']))
+
+ # gestion de l'ombre portée
+ if (options.has_key('shadow')) :
+ if (len(items)) :
+ target = items
+ else:
+ target = item
+ shadows.extend(graphicitem_shadow(widget,
+ target, **options['shadow']))
+
+
+ if len(reliefs):
+ items.extend(reliefs)
+ if len(shadows):
+ items.extend(shadows)
+
+ if len(items):
+ return items
+ else:
+ return item
+
+def repeat_zinc_item(widget,
+ item,
+ num = 2,
+ dxy = (0,0),
+ angle = None,
+ params = None,
+ copytag = None) :
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::repeat_zinc_item
+ # Duplication (clonage) d'un objet Zinc de représentation
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant du widget zinc
+ # item : <tagOrId> identifiant de l'item source
+ # options :
+ # -num : <n> nombre d'item total (par defaut 2)
+ # -dxy : <[delta_x, delta_y]> translation entre 2 duplications (par defaut [0,0])
+ # -angle : <angle> rotation entre 2 duplications
+ # -copytag : <sting> ajout d'un tag indexé pour chaque copie
+ # -params : <hashtable> {clef => [value list]}> valeur de paramètre
+ # de chaque copie
+ #---------------------------------------------------------------------------
+ """
+ clones = []
+ delta_x, delta_y = dxy
+ # duplication d'une liste d'items -> appel récursif
+ if (type(item) in (types.TupleType, types.ListType)) :
+ for part in item :
+ clones.append(repeat_zinc_item(widget,
+ part,
+ dxy,
+ angle,
+ params,
+ copytag))
+
+ return clones
+
+ tags = []
+
+ if (copytag) :
+ tags = widget.itemcget(item, 'tags')
+ widget.itemconfigure(item, tags = tags + ("%s0"%copytag,))
+
+ for i in xrange(1, num) :
+ clone = None
+
+ if (copytag) :
+ clone = widget.clone(item, tags = tags + ("%s%s"%(copytag, i),))
+ else :
+ clone = widget.clone(item)
+
+ clones.append(clone)
+ widget.translate(clone, delta_x*i, delta_y*i)
+ if angle :
+ widget.rotate(clone, radians(angle*i))
+
+ if (params is not None ) :
+ widget.itemconfigure(clone, **params )
+ return clones
+
+
+#MUST BE TESTED
+def meta_coords( type,
+ coords,
+ **options ):
+ """
+ #---------------------------------------------------------------------------
+ # FONCTIONS GEOMETRIQUES
+ #---------------------------------------------------------------------------
+
+ #---------------------------------------------------------------------------
+ # Graphics::meta_coords
+ # retourne une liste de coordonnées en utilisant la fonction du type
+ # d'item spécifié
+ #---------------------------------------------------------------------------
+ # paramètres : (passés par %options)
+ # -type : <string> type de primitive utilisée
+ # -coords : <coordsList> coordonnées nécessitée par la fonction [type]_coords
+ #
+ # les autres options spécialisées au type seront passés
+ # à la fonction [type]coords
+ #---------------------------------------------------------------------------
+ """
+ pts = None
+
+ if (type == 'roundedrectangle'):
+ log('Coords for roundedrectangle')
+ pts = rounded_rectangle_coords(coords, **options)
+
+ elif (type == 'hippodrome') :
+ log('Coords for hippodrome')
+ pts = hippodrome_coords(coords, **options)
+
+ elif (type == 'ellipse') :
+ log('Coords for ellipse')
+ pts = ellipse_coords(coords, **options)
+
+ elif (type == 'roundedcurve') :
+ log('Coords for roundedcurve')
+ pts = roundedcurve_coords(coords, **options)
+
+ elif (type == 'polygone') :
+ log('Coords for polygone')
+ pts = polygon_coords(coords, **options)
+
+ elif (type == 'polyline') :
+ log('Coords for polyline')
+ pts = polyline_coords(coords, **options)
+
+ elif (type == 'curveline') :
+ log('Coords for curveline')
+ pts = curveline_coords(coords, **options)
+
+ return pts
+
+
+def zincitem_2_curvecoords( widget, item,
+ linear = 0,
+ realcoords = 0,
+ adjust = 1,
+ ):
+ """
+ #--------------------------------------------------------------------------
+ # Graphics::zincitem_2_curvecoords
+ # retourne une liste des coordonnées 'Curve' d'un l'item Zinc
+ # rectangle, arc ou curve
+ #--------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant du widget zinc
+ # item : <tagOrId> identifiant de l'item source
+ # options :
+ # -linear : <boolean> réduction à des segments non curviligne
+ # (par défaut 0)
+ # -realcoords : <boolean> coordonnées à transformer dans le groupe père
+ # (par défaut 0)
+ # -adjust : <boolean> ajustement de la courbe de bezier (par défaut 1)
+ #--------------------------------------------------------------------------
+ """
+ itemtype = widget.type(item)
+
+ if not itemtype :
+ raise ValueError("Not a Valid Item %s" % item)
+
+ itemcoords = widget.coords(item)
+ coords = None
+ multi = []
+
+ if (itemtype == 'rectangle') :
+ coords = rounded_rectangle_coords(itemcoords, radius = 0)
+
+ elif (itemtype == 'arc') :
+ coords = ellipse_coords(itemcoords)
+ if linear :
+ coords = curve2polyline_coords(coords, adjust)
+
+ elif (itemtype == 'curve') :
+ numcontours = widget.contour(item)
+
+ if (numcontours < 2) :
+ if linear:
+ coords = curve2polyline_coords(itemcoords, adjust)
+ else :
+ if (linear) :
+ multi = curveitem2polyline_coords(widget, item)
+
+ else :
+ for contour in xrange(0, numcontours):
+ points = widget.coords(item, contour)
+ multi.extend(points)
+ coords = multi
+
+ if (realcoords) :
+ parentgroup = widget.group(item)
+ if (len(multi)) :
+ newcoords = []
+ for points in multi :
+ transcoords = widget.transform(item, parentgroup, points)
+ newcoords.extend(transcoords)
+ coords = newcoords
+ else :
+ transcoords = widget.transform(item, parentgroup, coords)
+ coords = transcoords
+
+ return coords
+
+def rounded_rectangle_coords( coords, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::rounded_rectangle_coords
+ # calcul des coords du rectangle à coins arrondis
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : <coordsList> coordonnées bbox (haut-gauche et bas-droite)
+ # du rectangle
+ # options :
+ # -radius : <dimension> rayon de raccord d'angle
+ # -corners : <booleanList> liste des raccords de sommets
+ # [0 (aucun raccord)|1] par défaut [1,1,1,1]
+ #---------------------------------------------------------------------------
+ """
+ (x_0, y_0, x_n, y_n) = (coords[0][0], coords[0][1],
+ coords[1][0], coords[1][1])
+
+ if (options.has_key('radius')):
+ radius = options['radius']
+ else:
+ radius = None
+
+ if (options.has_key('corners')):
+ corners = options['corners']
+ else:
+ corners = [1, 1, 1, 1]
+
+ # attention aux formes 'négatives'
+ if (x_n < x_0) :
+ (x_0, x_n) = (x_n, x_0)
+
+ if (y_n < y_0) :
+ (y_0, y_n) = (y_n, y_0)
+
+ height = min(x_n -x_0, y_n - y_0)
+ #radius non defini dans les parametres
+ if (radius is None) :
+ radius = int(height/10)
+ radius = max(radius, 3)
+
+ #radius defini mais trop petit
+ if ( radius < 2) :
+ return ((x_0, y_0), (x_0, y_n), (x_n, y_n), (x_n, y_0))
+
+ # correction de radius si necessaire
+ max_rad = height
+ #CODE BIZARRE
+ #Comment corners ne peut être non défini
+ #a ce niveau ?
+ # max_rad /= 2 if (!defined corners)
+ if (corners is None):
+ max_rad /= 2
+ radius = min(max_rad, radius)
+
+ # points remarquables
+ ptd_delta = radius * const_ptd_factor
+ (x_2, x_3) = (x_0 + radius, x_n - radius)
+ (x_1, x_4) = (x_2 - ptd_delta, x_3 + ptd_delta)
+ (y_2, y_3) = (y_0 + radius, y_n - radius)
+ (y_1, y_4) = (y_2 - ptd_delta, y_3 + ptd_delta)
+
+ # liste des 4 points sommet du rectangle : angles sans raccord circulaire
+ angle_pts = ((x_0, y_0), (x_0, y_n), (x_n, y_n), (x_n, y_0))
+
+ # liste des 4 segments quadratique : raccord d'angle = radius
+ roundeds = [[(x_2, y_0), (x_1, y_0, 'c'), (x_0, y_1, 'c'), (x_0, y_2),],
+ [(x_0, y_3), (x_0, y_4, 'c'), (x_1, y_n, 'c'), (x_2, y_n),],
+ [(x_3, y_n), (x_4, y_n, 'c'), (x_n, y_4, 'c'), (x_n, y_3),],
+ [(x_n, y_2), (x_n, y_1, 'c'), (x_4, y_0, 'c'), (x_3, y_0),]]
+
+ pts = []
+ previous = None
+ for i in xrange(0, 4):
+ #BUGS ??
+ if (corners[i]):
+ if (previous is not None) :
+ # on teste si non duplication de point
+ (nx, ny) = roundeds[i][0]
+ if (previous[0] == nx and previous[1] == ny) :
+ pts.pop()
+ pts.extend(roundeds[i])
+ previous = roundeds[i][3]
+ else :
+ pts.append(angle_pts[i])
+
+ return pts
+
+def ellipse_coords(coords, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::ellipse_coords
+ # calcul des coords d'une ellipse
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : <coordsList> coordonnées bbox du rectangle exinscrit
+ # options :
+ # -corners : <booleanList> liste des raccords de sommets
+ # [0 (aucun raccord)|1] par défaut [1,1,1,1]
+ #---------------------------------------------------------------------------
+ """
+ (x_0, y_0, x_n, y_n) = (coords[0][0], coords[0][1],
+ coords[1][0], coords[1][1])
+
+ if options.has_key('corners') :
+ corners = options.has_key('corners')
+ else:
+ corners = [1, 1, 1, 1]
+
+ # attention aux formes 'négatives'
+ if (x_n < x_0) :
+ xs = x_0
+ (x_0, x_n) = (x_n, xs)
+ if (y_n < y_0) :
+ ys = y_0
+ (y_0, y_n) = (y_n, ys)
+
+ # points remarquables
+ delta_x = (x_n - x_0)/2 * const_ptd_factor
+ delta_y = (y_n - y_0)/2 * const_ptd_factor
+ (x_2, y_2) = ((x_0+x_n)/2, (y_0+y_n)/2)
+ (x_1, x_3) = (x_2 - delta_x, x_2 + delta_x)
+ (y_1, y_3) = (y_2 - delta_y, y_2 + delta_y)
+
+ # liste des 4 points sommet de l'ellipse : angles sans raccord circulaire
+ angle_pts = ((x_0, y_0), (x_0, y_n), (x_n, y_n), (x_n, y_0))
+
+ # liste des 4 segments quadratique : raccord d'angle = arc d'ellipse
+ roundeds = (((x_2, y_0), (x_1, y_0, 'c'), (x_0, y_1, 'c'), (x_0, y_2), ),
+ ((x_0, y_2), (x_0, y_3, 'c'), (x_1, y_n, 'c'), (x_2, y_n), ),
+ ((x_2, y_n), (x_3, y_n, 'c'), (x_n, y_3, 'c'), (x_n, y_2), ),
+ ((x_n, y_2), (x_n, y_1, 'c'), (x_3, y_0, 'c'), (x_2, y_0), ))
+
+ pts = []
+ previous = None
+ for i in xrange(0, 4):
+ if (corners[i]) :
+ if (previous) :
+ # on teste si non duplication de point
+ (nx, ny) = roundeds[i][0]
+ if (previous[0] == nx and previous[1] == ny) :
+ pts.pop()
+
+
+ pts.extend(roundeds[i])
+ previous = roundeds[i][3]
+
+ else :
+ pts.append(angle_pts[i])
+
+ return pts
+
+
+def hippodrome_coords(coords, **options) :
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::hippodrome_coords
+ # calcul des coords d'un hippodrome
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : <coordsList> coordonnées bbox du rectangle exinscrit
+ # options :
+ # -orientation : orientation forcée de l'hippodrome [horizontal|vertical]
+ # -corners : liste des raccords de sommets [0|1] par défaut [1,1,1,1]
+ # -trunc : troncatures [left|right|top|bottom|both]
+ #---------------------------------------------------------------------------
+ """
+ (x_0, y_0, x_n, y_n) = (coords[0][0],
+ coords[0][1],
+ coords[1][0],
+ coords[1][1])
+
+ if (options.has_key('orientation')) :
+ orientation = options['orientation']
+ else:
+ orientation = 'none'
+
+ # orientation forcée de l'hippodrome
+ # (sinon hippodrome sur le plus petit coté)
+ if (orientation == 'horizontal') :
+ height = abs(y_n - y_0)
+ elif (orientation == 'vertical') :
+ height = abs(x_n - x_0)
+ else:
+ height = min(abs(x_n - x_0), abs(y_n - y_0))
+ radius = height/2
+ corners = (1, 1, 1, 1)
+
+ if (options.has_key('corners')) :
+ corners = options['corners']
+
+ elif (options.has_key('trunc')) :
+ trunc = options['trunc']
+ if (trunc == 'both') :
+ return ((x_0, y_0), (x_0, y_n), (x_n, y_n), (x_n, y_0))
+ else :
+ if (trunc == 'left'):
+ corners = (0, 0, 1, 1)
+ elif (trunc == 'right'):
+ corners = (1, 1, 0, 0)
+ elif (trunc == 'top'):
+ corners = (0, 1, 1, 0)
+ elif (trunc == 'bottom') :
+ corners = (1, 0, 0, 1)
+ else :
+ corners = (1, 1, 1, 1)
+
+ # l'hippodrome est un cas particulier de roundedRectangle
+ # on retourne en passant la 'configuration' à la fonction
+ # générique rounded_rectangle_coords
+ return rounded_rectangle_coords(coords,
+ radius = radius,
+ corners = corners)
+
+def polygon_coords(coords, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::polygon_coords
+ # calcul des coords d'un polygone régulier
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : <coords> point centre du polygone
+ # options :
+ # -numsides : <integer> nombre de cotés
+ # -radius : <dimension> rayon de définition du polygone
+ # (distance centre-sommets)
+ # -inner_radius : <dimension> rayon interne (polygone type étoile)
+ # -corners : <booleanList> liste des raccords de sommets [0|1]
+ # par défaut [1,1,1,1]
+ # -corner_radius : <dimension> rayon de raccord des cotés
+ # -startangle : <angle> angle de départ en degré du polygone
+ #---------------------------------------------------------------------------
+ """
+ if options.has_key('numsides'):
+ numsides = options['numsides']
+ else :
+ numsides = 0
+ if options.has_key('radius'):
+ radius = options['radius']
+ else:
+ radius = None
+ if (numsides < 3 or not radius) :
+ raise ValueError("Vous devez au moins spécifier "
+ +"un nombre de cotés >= 3 et un rayon...\n")
+
+ if (coords is None):
+ coords = (0, 0)
+ if (options.has_key('startangle')) :
+ startangle = options['startangle']
+ else:
+ startangle = 0
+ anglestep = 360/numsides
+ if options.has_key('inner_radius'):
+ inner_radius = options['inner_radius']
+ else:
+ inner_radius = None
+ pts = []
+
+ # points du polygone
+ for i in xrange(0, numsides):
+ (xp, yp) = rad_point(coords, radius, startangle + (anglestep*i))
+ pts.append((xp, yp))
+
+ # polygones 'étoiles'
+ if (inner_radius) :
+ (xp, yp) = rad_point(coords, inner_radius,
+ startangle + (anglestep*(i+ 0.5)))
+ pts.append((xp, yp))
+
+ pts.reverse()
+
+ if (options.has_key('corner_radius')) :
+ if options.has_key('corners'):
+ corners = options['corners']
+ else:
+ corners = None
+ return roundedcurve_coords(pts,
+ radius = options['corner_radius'],
+ corners = corners)
+ else :
+ return pts
+
+
+def rounded_angle(widget, parentgroup, coords, radius) :
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::rounded_angle
+ # THIS FUNCTION IS NO MORE USED, NEITHER EXPORTED
+ # curve d'angle avec raccord circulaire
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : identifiant du widget Zinc
+ # parentgroup : <tagOrId> identifiant de l'item group parent
+ # coords : <coordsList> les 3 points de l'angle
+ # radius : <dimension> rayon de raccord
+ #---------------------------------------------------------------------------
+ """
+ (pt0, pt1, pt2) = coords
+
+ (corner_pts, center_pts) = rounded_angle_coords(coords, radius)
+ (cx_0, cy_0) = center_pts
+
+ if (parentgroup is None) :
+ parentgroup = 1
+
+ pts = [pt0]
+ pts.extend(corner_pts)
+ pts.append(pt2)
+
+ widget.add('curve',
+ parentgroup,
+ lpts2coords(pts),
+ closed = 0,
+ linewidth = 1,
+ priority = 20,
+ )
+
+
+def rounded_angle_coords (coords, radius) :
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::rounded_angle_coords
+ # calcul des coords d'un raccord d'angle circulaire
+ #---------------------------------------------------------------------------
+ # le raccord circulaire de 2 droites sécantes est traditionnellement
+ # réalisé par un
+ # arc (conique) du cercle inscrit de rayon radius tangent à ces 2 droites
+ #
+ # Quadratique :
+ # une approche de cette courbe peut être réalisée simplement par le calcul
+ # de 4 points
+ # spécifiques qui définiront - quelle que soit la valeur de l'angle formé
+ # par les 2
+ # droites - le segment de raccord :
+ # - les 2 points de tangence au cercle inscrit seront les points de début
+ # et de fin
+ # du segment de raccord
+ # - les 2 points de controle seront situés chacun sur le vecteur
+ # reliant le point de
+ # tangence au sommet de l'angle (point secant des 2 droites)
+ # leur position sur ce vecteur peut être simplifiée comme suit :
+ # - à un facteur de 0.5523 de la distance au sommet pour
+ # un angle >= 90° et <= 270°
+ # - à une 'réduction' de ce point vers le point de tangence
+ # pour les angles limites
+ # de 90° vers 0° et de 270° vers 360°
+ # ce facteur sera légérement modulé pour recouvrir plus précisement
+ # l'arc correspondant
+ #---------------------------------------------------------------------------
+ # coords : <coordsList> les 3 points de l'angle
+ # radius : <dimension> rayon de raccord
+ #---------------------------------------------------------------------------
+ """
+ (pt0, pt1, pt2) = coords
+
+ # valeur d'angle et angle formé par la bisectrice
+ (angle, bisecangle) = vertex_angle(pt0, pt1, pt2)
+
+ # distance au centre du cercle inscrit : rayon/sinus demi-angle
+ asin = sin(radians(angle/2))
+
+ if (asin) :
+ delta = abs(radius / asin)
+ else:
+ delta = radius
+
+ # point centre du cercle inscrit de rayon $radius
+ if (angle < 180) :
+ refangle = bisecangle + 90
+ else :
+ refangle = bisecangle - 90
+
+ (cx_0, cy_0) = rad_point(pt1, delta, refangle)
+
+ # points de tangeance : pts perpendiculaires du centre aux 2 droites
+ (px_1, py_1) = perpendicular_point((cx_0, cy_0), (pt0, pt1))
+ (px_2, py_2) = perpendicular_point((cx_0, cy_0), (pt1, pt2))
+
+ # point de controle de la quadratique
+ # facteur de positionnement sur le vecteur pt.tangence, sommet
+ ptd_factor = const_ptd_factor
+ if (angle < 90 or angle > 270) :
+ if (angle < 90) :
+ diffangle = angle
+ else:
+ diffangle = 360 - angle
+ if (diffangle > 15) :
+ ptd_factor -= (((90 - diffangle)/90) * (ptd_factor/4))
+ ptd_factor = (diffangle/90) * (ptd_factor
+ + ((1 - ptd_factor)
+ * (90 - diffangle)/90))
+ else :
+ diffangle = abs(180 - angle)
+ if (diffangle > 15) :
+ ptd_factor += (((90 - diffangle)/90) * (ptd_factor/3))
+
+ # delta xy aux pts de tangence
+ (d1x, d1y) = ((pt1[0] - px_1) * ptd_factor, (pt1[1] - py_1) * ptd_factor)
+ (d2x, d2y) = ((pt1[0] - px_2) * ptd_factor, (pt1[1] - py_2) * ptd_factor)
+
+ # les 4 points de l'arc 'quadratique'
+ corner_pts = [(px_1, py_1), (px_1+d1x, py_1+d1y, 'c'),
+ (px_2+d2x, py_2+d2y, 'c'), (px_2, py_2)]
+
+
+ # retourne le segment de quadratique et le centre du cercle inscrit
+ return (corner_pts, (cx_0, cy_0))
+
+
+def roundedcurve_coords(coords, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::roundedcurve_coords
+ # retourne les coordonnées d'une curve à coins arrondis
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : <coordsList> liste de coordonnées des points de la curve
+ # options :
+ # -radius : <dimension> rayon de raccord d'angle
+ # -corners : <booleanList> liste des raccords de sommets [0|1]
+ # par défaut [1,1,1,1]
+ #---------------------------------------------------------------------------
+ """
+ numfaces = len(coords)
+ curve_pts = []
+
+ if (options.has_key('radius')) :
+ radius = options['radius']
+ else:
+ radius = 0
+ corners = None
+ if options.has_key('corners') :
+ corners = options['corners']
+
+ for index in xrange(numfaces):
+ if (corners is not None) :
+ if (index+1 > len(corners)) or not corners[index] :
+ curve_pts.append(coords[index])
+ continue
+
+ if (index) :
+ prev = index - 1
+ else :
+ prev = numfaces - 1
+ if (index > numfaces - 2) :
+ next = 0
+ else :
+ next = index + 1
+ anglecoords = (coords[prev], coords[index], coords[next])
+
+ quad_pts = rounded_angle_coords(anglecoords, radius)[0]
+ curve_pts.extend(quad_pts)
+ return curve_pts
+
+
+def polyline_coords(coords, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::polyline_coords
+ # retourne les coordonnées d'une polyline
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : <coordsList> liste de coordonnées des sommets de la polyline
+ # options :
+ # -radius : <dimension> rayon global de raccord d'angle
+ # -corners : <booleanList> liste des raccords de sommets [0|1]
+ # par défaut [1,1,1,1],
+ # -corners_radius : <dimensionList> liste des rayons de raccords de sommets
+ #---------------------------------------------------------------------------
+ """
+ numfaces = len(coords)
+ curve_pts = []
+
+ if (options.has_key('radius')) :
+ radius = options['radius']
+ else:
+ radius = 0
+ if options.has_key('corners_radius'):
+ corners_radius = options['corners_radius']
+ corners = corners_radius
+ else:
+ corners_radius = None
+ if options.has_key('corners'):
+ corners = options['corners']
+ else:
+ corners = None
+
+ for index in xrange(0, numfaces):
+ if (corners is not None
+ and (len(corners) - 1 < index
+ or not corners[index])):
+ curve_pts.append(coords[index])
+ else :
+ if (index) :
+ prev = index - 1
+ else:
+ prev = numfaces - 1
+ if (index > numfaces - 2) :
+ next = 0
+ else:
+ next = index + 1
+ anglecoords = (coords[prev], coords[index], coords[next])
+
+ if (corners_radius) :
+ rad = corners_radius[index]
+ else:
+ rad = radius
+ quad_pts = rounded_angle_coords(anglecoords, rad)[0]
+ curve_pts.extend(quad_pts)
+
+ return curve_pts
+
+def pathline_coords (coords, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::pathline_coords
+ # retourne les coordonnées d'une pathline
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : <coordsList> liste de coordonnées des points du path
+ # options :
+ # -closed : <boolean> ligne fermée
+ # -shifting : <out|center|in> sens de décalage du path (par défaut center)
+ # -linewidth : <dimension> epaisseur de la ligne
+ #---------------------------------------------------------------------------
+ """
+ numfaces = len(coords)
+ pts = []
+
+ if options.has_key('closed'):
+ closed = options['closed']
+ else:
+ closed = None
+ if (options.has_key('linewidth')) :
+ linewidth = options['linewidth']
+ else:
+ linewidth = 2
+
+ if (options.has_key('shifting')) :
+ shifting = options['shifting']
+ else:
+ shifting = 'center'
+
+ if ( not numfaces or linewidth < 2):
+ raise ValueError("Invalid PathLine_coords")
+
+ if (closed) :
+ previous = coords[numfaces - 1]
+ else:
+ previous = None
+
+ next = coords[1]
+ if (shifting == 'center'):
+ linewidth /= 2
+
+ for i in xrange(0, numfaces):
+ pt = coords[i]
+
+ if (previous is None) :
+ # extrémité de curve sans raccord -> angle plat
+ previous = (pt[0] + (pt[0] - next[0]), pt[1] + (pt[1] - next[1]))
+
+ (angle, bisecangle) = vertex_angle(previous, pt, next)
+
+ # distance au centre du cercle inscrit : rayon/sinus demi-angle
+ asin = sin(radians(angle/2))
+ if (asin) :
+ delta = abs(linewidth / asin)
+ else:
+ delta = linewidth
+
+ if (shifting == 'out' or shifting == 'in') :
+ if (shifting == 'out') :
+ adding = -90
+ else:
+ adding = 90
+ pts.append(rad_point(pt, delta, bisecangle + adding))
+ pts.append(pt)
+
+ else :
+ pts.append(rad_point(pt, delta, bisecangle-90))
+ pts.append(rad_point(pt, delta, bisecangle+90))
+
+ if (i == numfaces - 2) :
+ if (closed) :
+ next = coords[0]
+ else:
+ next = (coords[i+1][0] + (coords[i+1][0] - pt[0]),
+ coords[i+1][1] + (coords[i+1][1] - pt[1]))
+ elif (i == numfaces - 1):
+ next = None
+ else :
+ next = coords[i+2]
+
+ previous = coords[i]
+
+ if (closed) :
+ pts.extend((pts[0], pts[1], pts[2], pts[3]))
+
+ return pts
+
+
+def curveline_coords(coords, **options) :
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::curveline_coords
+ # retourne les coordonnées d'une curveLine
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : <coordsList> liste de coordonnées des points de la ligne
+ # options :
+ # -closed : <boolean> ligne fermée
+ # -shifting : <out|center|in> sens de décalage du contour
+ # (par défaut center)
+ # -linewidth : <dimension> epaisseur de la ligne
+ #---------------------------------------------------------------------------
+ """
+ numfaces = len(coords)
+ gopts = []
+ backpts = []
+ pts = []
+
+ if options.has_key('closed'):
+ closed = options['closed']
+ else:
+ closed = None
+ if (options.has_key('linewidth')) :
+ linewidth = options['linewidth']
+ else:
+ linewidth = 2
+ if (options.has_key('shifting')) :
+ shifting = options['shifting']
+ else:
+ shifting = 'center'
+
+ if( not numfaces or linewidth < 2):
+ raise ValueError("Bad coords %s or linewidth %s"%(numfaces, linewidth))
+
+ if (closed) :
+ previous = coords[numfaces - 1]
+ else:
+ previous = None
+
+ next = coords[1]
+ if (shifting == 'center'):
+ linewidth /= 2
+
+ for i in xrange(0, numfaces):
+ pt = coords[i]
+
+ if ( previous is None ) :
+ # extrémité de curve sans raccord -> angle plat
+ previous = (pt[0] + (pt[0] - next[0]), pt[1] + (pt[1] - next[1]))
+
+
+ (angle, bisecangle) = vertex_angle(previous, pt, next)
+
+ # distance au centre du cercle inscrit : rayon/sinus demi-angle
+ asin = sin(radians(angle/2))
+ if (asin) :
+ delta = abs(linewidth / asin)
+ else:
+ delta = linewidth
+
+ if (shifting == 'out' or shifting == 'in') :
+ if (shifting == 'out') :
+ adding = -90
+ else:
+ adding = 90
+ pts.append(rad_point(pt, delta, bisecangle + adding))
+ pts.append(pt)
+
+ else :
+ pts = rad_point(pt, delta, bisecangle+90)
+ gopts.append(pts)
+ pts = rad_point(pt, delta, bisecangle-90)
+ backpts.insert(0, pts)
+
+ if (i == numfaces - 2) :
+ if (closed) :
+ next = coords[0]
+ else:
+ next = (coords[i+1][0] +
+ (coords[i+1][0] - pt[0]), coords[i+1][1]
+ + (coords[i+1][1] - pt[1]))
+ else :
+ next = coords[i+2]
+
+ previous = coords[i]
+
+ gopts.extend(backpts)
+
+ if (closed) :
+ gopts.extend ((gopts[0], gopts[1]))
+
+ return gopts
+
+
+def shiftpath_coords(coords, **options) :
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::shiftpath_coords
+ # retourne les coordonnées d'un décalage de path
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : <coordsList> liste de coordonnées des points du path
+ # options :
+ # -closed : <boolean> ligne fermée
+ # -shifting : <'out'|'in'> sens de décalage du path (par défaut out)
+ # -width : <dimension> largeur de décalage (par défaut 1)
+ #---------------------------------------------------------------------------
+ """
+ numfaces = len(coords)
+
+ if options.has_key('closed'):
+ closed = options['closed']
+ else:
+ closed = None
+ if (options.has_key('width')) :
+ width = options['width']
+ else:
+ width = 1
+ if (options.has_key('shifting')) :
+ shifting = options['shifting']
+ else:
+ shifting = 'out'
+
+ if (not numfaces or not width):
+ return coords
+
+ pts = []
+
+ if (closed) :
+ previous = coords[numfaces - 1]
+ else:
+ previous = None
+ next = coords[1]
+
+ for i in xrange(0, numfaces):
+ pt = coords[i]
+
+ if ( previous is None ) :
+ # extrémité de curve sans raccord -> angle plat
+ previous = (pt[0] + (pt[0] - next[0]), pt[1] + (pt[1] - next[1]))
+
+
+ (angle, bisecangle) = vertex_angle(previous, pt, next)
+
+ # distance au centre du cercle inscrit : rayon/sinus demi-angle
+ asin = sin(radians(angle/2))
+ if (asin) :
+ delta = abs(width / asin)
+ else:
+ delta = width
+
+ if (shifting == 'out') :
+ adding = -90
+ else:
+ adding = 90
+ (x, y) = rad_point(pt, delta, bisecangle + adding)
+ pts.append((x, y))
+
+
+ if (i > numfaces - 3) :
+ if (closed) :
+ next = coords[0]
+ else:
+ next = (pt[0] + (pt[0] - previous[0]),
+ pt[1] + (pt[1] - previous[1]))
+
+ else :
+ next = coords[i+2]
+
+ previous = coords[i]
+
+ return pts
+
+
+
+
+def curveitem2polyline_coords(widget, item, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::curveitem2polyline_coords
+ # Conversion des coordonnées Znitem curve (multicontours)
+ # en coordonnées polyline(s)
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant du widget zinc
+ # item : <tagOrId> identifiant de l'item source
+ # options :
+ # -tunits : <integer> nombre pas de division des segments bezier
+ # (par défaut 20)
+ # -adjust : <boolean> ajustement de la courbe de bezier (par défaut 1)
+ #---------------------------------------------------------------------------
+ """
+ if (not widget.type(item)):
+ raise ValueError("Item Not Found")
+ coords = []
+ numcontours = widget.contour(item)
+ #parentgroup = widget.group(item)
+
+ for contour in xrange(0, numcontours):
+ points = widget.coords(item, contour)
+ contourcoords = curve2polyline_coords(points, **options)
+
+ coords.append(contourcoords)
+
+ return coords
+
+def curve2polyline_coords(points, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::curve2polyline_coords
+ # Conversion curve -> polygone
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # points : <coordsList> liste des coordonnées curve à transformer
+ # options :
+ # -tunits : <integer> nombre pas de division des segments bezier
+ # (par défaut 20)
+ # -adjust : <boolean> ajustement de la courbe de bezier (par défaut 1)
+ #---------------------------------------------------------------------------
+ """
+ if (options.has_key('tunits')) :
+ tunits = options['tunits']
+ else:
+ tunits = 20
+ if (options.has_key('adjust')) :
+ adjust = options['adjust']
+ else:
+ adjust = 1
+
+ poly = []
+ previous = None
+ bseg = []
+ numseg = 0
+ #prevtype = None
+
+ for point in points:
+ if len(point) == 3:
+ (x, y, c) = point
+ elif len(point) == 2:
+ (x, y, c) = (point, None)
+ else:
+ ValueError("Bad point")
+ if (c == 'c') :
+ if not len(bseg) and previous:
+ bseg.append(previous)
+ bseg.append(point)
+
+ else :
+ if (len (bseg)) :
+ bseg.append(point)
+ if (adjust) :
+ pts = bezier_compute(bseg, skipend = 1)
+ del pts[0]
+ del pts[0]
+ poly.extend(pts)
+
+ else :
+ pts = bezier_segment(bseg, tunits = tunits, skipend = 1)
+ del pts[0]
+ del pts[0]
+ poly.extend(pts)
+
+ bseg = []
+ numseg += 1
+ #prevtype = 'bseg'
+
+ else :
+ poly.append((x, y))
+ #prevtype = 'line'
+
+ previous = point
+
+
+ return poly
+
+
+def build_tabboxitem(widget, parentgroup, **options):
+ """
+ #-------------------------------------------------------------------------------
+ # Graphics::build_tabboxitem
+ # construit les items de représentations Zinc d'une boite à onglets
+ #-------------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant du widget zinc
+ # parentgroup : <tagOrId> identifiant de l'item group parent
+ #
+ # options :
+ # -coords : <coordsList> coordonnées haut-gauche et bas-droite
+ # du rectangle
+ # englobant du Tabbox
+ # -params : <hastable> arguments spécifiques des items curve
+ # à passer au widget
+ # -texture : <imagefile> ajout d'une texture aux items curve
+ # -tabtitles : <hashtable> table de hash de définition des titres onglets
+ # -pageitems : <hashtable> table de hash de définition des pages internes
+ # -relief : <hashtable> table de hash de définition du relief de forme
+ #
+ # (options de construction géometrique passées à tabbox_coords)
+ # -numpages : <integer> nombre de pages (onglets) de la boite
+ # -anchor : <'n'|'e'|'s'|'w'> ancrage (positionnement) de la ligne
+ # d'onglets
+ # -alignment : <'left'|'center'|'right'> alignement des onglets sur le coté
+ # d'ancrage
+ # -tabwidth : <'auto'>|<dimension>|<dimensionList> : largeur des onglets
+ # 'auto' largeur répartie, les largeurs sont auto-ajustée
+ # si besoin.
+ # -tabheight : <'auto'>|<dimension> : hauteur des onglets
+ # -tabshift : <'auto'>|<dimension> offset de 'biseau' entre base et haut de
+ # l'onglet (défaut auto)
+ # -radius : <dimension> rayon des arrondis d'angle
+ # -overlap : <'auto'>|<dimension> offset de recouvrement/séparation entre
+ # onglets
+ # -corners : <booleanList> liste 'spécifique' des raccords de sommets [0|1]
+ #---------------------------------------------------------------------------
+ """
+ if options.has_key('coords') :
+ coords = options['coords']
+ else:
+ raise ValueError("Coords needed")
+ if options.has_key('params'):
+ params = options['params']
+ else:
+ params = {}
+ if params.has_key('tags'):
+ tags = params['tags']
+ else :
+ tags = []
+ texture = None
+
+ if (options.has_key('texture')) :
+ texture = get_texture(widget,
+ options['texture'])
+
+
+ if options.has_key('tabtitles'):
+ titlestyle = options['tabtitles']
+ else :
+ titlestyle = None
+ if (titlestyle) :
+ titles = titlestyle['text']
+ else:
+ titles = None
+
+ tabs = []
+ (shapes, tcoords, invert) = tabbox_coords(**options)
+ if (invert) :
+ k = len(shapes)
+ else:
+ k = -1
+ shapes.reverse()
+ for shape in shapes :
+ if (invert) :
+ k -= 1
+ else :
+ k += +1
+ group = widget.add('group', parentgroup)
+ params['tags'] = tags
+ params['tags'] += (k, 'intercalaire')
+ form = widget.add('curve',
+ group,
+ lpts2coords(shape),
+ **params)
+ if texture :
+ widget.itemconfigure(form, tile = texture)
+
+ if (options.has_key('relief')) :
+ graphicitem_relief(widget, form, **options['relief'])
+
+
+ if (options.has_key('page')) :
+ build_zinc_item(widget, group, **options['page'])
+
+ if (titles) :
+ if (invert) :
+ tindex = k
+ else:
+ tindex = len(shapes) - k
+ titlestyle['itemtype'] = 'text'
+ titlestyle['coords'] = tcoords[tindex]
+ titlestyle['params']['text'] = titles[tindex]
+ ltags = list(tags)
+ ltags.append(tindex)
+ ltags.append('titre')
+ titlestyle['params']['tags'] = tuple(ltags)
+ build_zinc_item(widget, group, **titlestyle)
+
+ return tabs
+
+
+def tabbox_coords(coords, **options):
+ """
+ #---------------------------------------------------------------------------
+ # tabbox_coords
+ # Calcul des shapes de boites à onglets
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : <coordList> coordonnées haut-gauche bas-droite du rectangle
+ # englobant de la tabbox
+ # options
+ # -numpages : <integer> nombre de pages (onglets) de la boite
+ # -anchor : <'n'|'e'|'s'|'w'> ancrage (positionnement) de la
+ # ligne d'onglets
+ # -alignment : <'left'|'center'|'right'> alignement des onglets
+ # sur le coté d'ancrage
+ # -tabwidth : <'auto'>|<dimension>|<dimensionList> : largeur des onglets
+ # 'auto' largeur répartie, les largeurs sont auto-ajustée
+ # si besoin.
+ # -tabheight : <'auto'>|<dimension> : hauteur des onglets
+ # -tabshift : <'auto'>|<dimension> offset de 'biseau' entre base et haut
+ # de l'onglet (défaut auto)
+ # -radius : <dimension> rayon des arrondis d'angle
+ # -overlap : <'auto'>|<dimension> offset de recouvrement/séparation
+ # entre onglets
+ # -corners : <booleanList> liste 'spécifique' des raccords
+ # de sommets [0|1]
+ #---------------------------------------------------------------------------
+ """
+ (x_0, y_0) = coords[0]
+ (x_n, y_n) = coords[1]
+ shapes, titles_coords = [], []
+ inverse = None
+
+ #loptions = options.keys()
+ if options.has_key('numpages'):
+ numpages = options['numpages']
+ else:
+ numpages = 0
+
+ if (not x_0 or not y_0 or not x_n or not y_n or not numpages) :
+ raise ValueError("Vous devez au minimum spécifier\
+ le rectangle englobant et le nombre de pages")
+
+ if (options.has_key('anchor')) :
+ anchor = options['anchor']
+ else:
+ anchor = 'n'
+ if (options.has_key('alignment')) :
+ alignment = options['alignment']
+ else:
+ alignment ='left'
+
+
+ if (options.has_key('tabwidth')) :
+ nlen = options['tabwidth']
+ else:
+ nlen ='auto'
+ if (options.has_key('tabheight')) :
+ thick = options['tabheight']
+ else:
+ thick ='auto'
+ if (options.has_key('tabshift')) :
+ biso = options['tabshift']
+ else:
+ biso = 'auto'
+ if (options.has_key('radius')) :
+ radius = options['radius']
+ else:
+ radius = 0
+ if (options.has_key('overlap')) :
+ overlap = options['overlap']
+ else:
+ overlap = 0
+ if (options.has_key('corners')):
+ corners = options['corners']
+ else:
+ corners = None
+ if (anchor in ( 'n', 's')) :
+ orientation = 'horizontal'
+ else:
+ orientation = 'vertical'
+ if (orientation == 'horizontal') :
+ maxwidth = (x_n - x_0)
+ else:
+ maxwidth = (y_n - y_0)
+ tabswidth = 0
+ align = 1
+
+ if (nlen == 'auto') :
+ tabswidth = maxwidth
+ nlen = float(tabswidth + (overlap * (numpages - 1)))/numpages
+ else :
+ if (type(nlen) in (types.TupleType, types.ListType )) :
+ for w in nlen :
+ tabswidth += (w - overlap)
+
+ tabswidth += overlap
+ else :
+ tabswidth = (nlen * numpages) - (overlap * (numpages - 1))
+
+
+ if (tabswidth > maxwidth) :
+ tabswidth = maxwidth
+ nlen = float(tabswidth + (overlap * (numpages - 1)))/numpages
+
+ if (alignment == 'center' and ((maxwidth - tabswidth) > radius)):
+ align = 0
+
+
+ if (thick == 'auto') :
+ if (orientation == 'horizontal') :
+ thick = int((y_n - y_0)/10)
+ else:
+ thick = int((x_n - y_0)/10)
+ thick = max(10, thick)
+ thick = min(40, thick)
+
+ if (biso == 'auto') :
+ biso = int(thick/2)
+
+ if ((alignment == 'right' and anchor != 'w') or
+ (anchor == 'w' and alignment != 'right')) :
+
+ if (type(nlen) in (types.TupleType, types.ListType)) :
+ for p in xrange(0, numpages):
+ nlen[p] *= -1
+ else :
+ nlen *= -1
+ biso *= -1
+ overlap *= -1
+
+ if (alignment == 'center') :
+ (biso1, biso2) = (biso/2, biso/2)
+ else:
+ (biso1, biso2) = (0, biso)
+
+ cadre, tabdxy = [], []
+ xref, yref = 0, 0
+ if (orientation == 'vertical') :
+ if (anchor == 'w'):
+ thick *= -1
+ if (anchor == 'w') :
+ (startx, endx) = (x_0, x_n)
+ else:
+ (startx, endx) = (x_n, x_0)
+ if ((anchor == 'w' and alignment != 'right') or
+ (anchor == 'e' and alignment == 'right')) :
+ (starty, endy) = (y_n, y_0)
+ else:
+ (starty, endy) = (y_0, y_n)
+
+ xref = startx - thick
+ yref = starty
+ if (alignment == 'center') :
+ if (anchor == 'w') :
+ ratio = -2
+ else:
+ ratio = 2
+ yref += (float(maxwidth - tabswidth)/ratio)
+
+ cadre = ((xref, endy), (endx, endy), (endx, starty), (xref, starty))
+
+ # flag de retournement de la liste des pts de curve si nécessaire
+ # -> sens anti-horaire
+ inverse = (alignment == 'right')
+
+ else :
+ if (anchor == 's'):
+ thick *= -1
+ (starty, endy) = (y_n, y_0)
+ else :
+ (starty, endy) = (y_0, y_n)
+
+ if (alignment == 'right') :
+ (startx, endx) = (x_n, x_0)
+ else:
+ (startx, endx) = (x_0, x_n)
+
+
+ yref = starty + thick
+ if (alignment == 'center') :
+ xref = x_0 + (float(maxwidth - tabswidth)/2)
+ else :
+ xref = startx
+
+ cadre = ((endx, yref), (endx, endy), (startx, endy), (startx, yref))
+
+ # flag de retournement de la liste des pts de curve si nécessaire
+ # -> sens anti-horaire
+ inverse = ((anchor == 'n' and alignment != 'right')
+ or (anchor == 's' and alignment == 'right'))
+
+
+ for i in xrange(0, numpages):
+ pts = []
+
+ # décrochage onglet
+ #push (pts, ([xref, yref])) if i > 0
+
+ # cadre
+ pts.extend(cadre)
+
+ # points onglets
+ if (i > 0 or not align) :
+ pts.append((xref, yref))
+
+ if (type(nlen) in (types.TupleType, types.ListType)) :
+ tw = nlen[i]
+ else:
+ tw = nlen
+
+ if (type(nlen) in (types.TupleType, types.ListType)) :
+ slen = len(nlen)
+ else:
+ slen = nlen
+
+ if (orientation == 'vertical') :
+ tabdxy = ((thick, biso1), (thick, tw - biso2), (0, tw))
+ else:
+ tabdxy = ((biso1, -thick), (tw - biso2, -thick), (tw, 0))
+ for delta_xy in tabdxy :
+ pts.append((xref + delta_xy[0], yref + delta_xy[1]))
+
+
+ if (radius) :
+ if (not options.has_key('corners')) :
+ if (i > 0 or not align) :
+ corners = (0, 1, 1, 0, 0, 1, 1, 0)
+ else :
+ corners = (0, 1, 1, 0, 1, 1, 0, 0, 0)
+
+ curvepts = roundedcurve_coords(pts,
+ radius = radius,
+ corners = corners)
+ lcurvepts = list(curvepts)
+ if (inverse):
+ lcurvepts.reverse()
+ shapes.append(lcurvepts)
+ else :
+ if (inverse):
+ pts.reverse()
+ shapes.append(pts)
+
+ if (orientation == 'horizontal') :
+ titles_coords.append((float(xref) + (tw - (biso2 - biso1))/2,
+ float(yref) - (thick/2)))
+ xref += (tw - overlap)
+
+ else :
+ titles_coords.append( (float(xref) + (thick/2),
+ yref + (slen - ((biso2 - biso1)/2))/2))
+ yref += (slen - overlap)
+
+ return (shapes, titles_coords, inverse)
+
+
+def graphicitem_relief(widget, item, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::graphicitem_relief
+ # construit un relief à l'item Zinc en utilisant des items Triangles
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant du widget zinc
+ # item : <tagOrId> identifiant de l'item zinc
+ # options : <hash> table d'options
+ # -closed : <boolean> le relief assure la fermeture de forme (défaut 1)
+ # -profil : <'rounded'|'flat'> type de profil (defaut 'rounded')
+ # -relief : <'raised'|'sunken'> (défaut 'raised')
+ # -side : <'inside'|'outside'> relief interne ou externe à la forme
+ # (défaut 'inside')
+ # -color : <color> couleur du relief (défaut couleur de la forme)
+ # -smoothed : <boolean> facettes relief lissées ou non (défaut 1)
+ # -lightangle : <angle> angle d'éclairage (défaut valeur générale widget)
+ # -width : <dimension> 'épaisseur' du relief en pixel
+ # -fine : <boolean> mode précision courbe de bezier
+ # (défaut 0 : auto-ajustée)
+ #-------------------------------------------------------------------------------
+ """
+ items = []
+
+ # relief d'une liste d'items -> appel récursif
+ if (type(item) in (types.TupleType, types.ListType)) :
+ for part in item :
+ items.extend(graphicitem_relief(widget, part, **options))
+ else :
+ itemtype = widget.type(item)
+ if not itemtype:
+ raise ValueError("Bad Item")
+
+ parentgroup = widget.group(item)
+ if (options.has_key('priority')) :
+ priority = options['priority']
+ else :
+ priority = widget.itemcget(item, 'priority')+1
+
+ # coords transformés (polyline) de l'item
+ adjust = not options['fine']
+ for coords in zincitem_2_curvecoords(widget,
+ item, linear = 1,
+ realcoords = 1,
+ adjust = adjust) :
+ (pts, colors) = polyline_relief_params(widget,
+ item,
+ coords,
+ **options)
+
+ items.append(widget.add('triangles',
+ parentgroup,
+ pts,
+ priority = priority,
+ colors = colors))
+
+
+ # renforcement du contour
+ if (widget.itemcget(item, 'linewidth')) :
+ items.append(widget.clone(item,
+ filled = 0,
+ priority = priority+1))
+
+ return items
+
+
+def polyline_relief_params(widget, item, coords, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::polyline_relief_params
+ # retourne la liste des points et des couleurs nécessaires à la construction
+ # de l'item Triangles du relief
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant widget Zinc
+ # item : <tagOrId> identifiant item Zinc
+ # options : <hash> table d'options
+ # -closed : <boolean> le relief assure la fermeture de forme (défaut 1)
+ # -profil : <'rounded'|'flat'> type de profil (defaut 'rounded')
+ # -relief : <'raised'|'sunken'> (défaut 'raised')
+ # -side : <'inside'|'outside'> relief interne ou externe à la forme
+ # (défaut 'inside')
+ # -color : <color> couleur du relief (défaut couleur de la forme)
+ # -smoothed : <boolean> facettes relief lissées ou non (défaut 1)
+ # -lightangle : <angle> angle d'éclairage (défaut valeur générale widget)
+ # -width : <dimension> 'épaisseur' du relief en pixel
+ #---------------------------------------------------------------------------
+ """
+
+ if (options.has_key('closed')) :
+ closed = options['closed']
+ else:
+ closed = 1
+ if (options.has_key('profil')) :
+ profil = options['profil']
+ else:
+ profil = 'rounded'
+ if (options.has_key('relief')) :
+ relief = options['relief']
+ else :
+ relief = 'raised'
+ if (options.has_key('side')) :
+ side = options['side']
+ else:
+ side = 'inside'
+ if (options.has_key('color')) :
+ basiccolor = options['color']
+ else:
+ basiccolor = zincitem_predominantcolor(widget, item)
+ if (options.has_key('smooth')) :
+ smoothed = options['smooth']
+ else:
+ smoothed = 1
+ if (options.has_key('lightangle')) :
+ lightangle = options['lightangle']
+ else:
+ lightangle = widget.cget('lightangle')
+
+ if options.has_key('width'):
+ width = options['width']
+ else:
+ raise ValueError('Options must have width field')
+ if ( width < 1) :
+ (x_0, y_0, x_1, y_1) = widget.bbox(item)
+ width = min(x_1 -x_0, y_1 - y_0)/10
+ if (width < 2) :
+ width = 2
+
+ numfaces = len(coords)
+ if (closed):
+ previous = coords[numfaces - 1]
+ else:
+ previous = None
+ next = coords[1]
+
+ pts = []
+ colors = []
+ alpha = 100
+ m = re.compile("^(?P<color>#[0-9a-fA-F]{6});(?P<alpha>\d{1,2})$")
+ res = m.match(basiccolor)
+ if (res is not None) :
+ (basiccolor, alpha) = res.group('color'), res.group('alpha')
+
+ if ( options.has_key('color')):
+ color = options['color']
+ res = m.match(color)
+ if ((res is None) and (profil == 'flat')):
+ alpha /= 2
+
+ if (profil == 'rounded') :
+ reliefalphas = [0, alpha]
+ else:
+ reliefalphas = [alpha, alpha]
+
+ for i in xrange(0, numfaces):
+ pt = coords[i]
+
+ if (previous) :
+ # extrémité de curve sans raccord -> angle plat
+ previous = (pt[0] + (pt[0] - next[0]), pt[1] + (pt[1] - next[1]))
+
+
+ (angle, bisecangle) = vertex_angle(previous, pt, next)
+
+ # distance au centre du cercle inscrit : rayon/sinus demi-angle
+ asin = sin(radians(angle/2))
+ if (asin) :
+ delta = abs(width / asin)
+ else:
+ delta = width
+ if (side == 'outside') :
+ decal = -90
+ else:
+ decal = 90
+
+ shift_pt = rad_point(pt, delta, bisecangle+decal)
+ pts.append(shift_pt)
+ pts.append(pt)
+
+ if (smoothed and i) :
+ pts.append(shift_pt)
+ pts.append(pt)
+
+
+ faceangle = 360 -(linenormal(previous, next)+90)
+
+ light = abs(lightangle - faceangle)
+ if (light > 180):
+ light = 360 - light
+ if light < 1:
+ light = 1
+
+ if (relief == 'sunken') :
+ lumratio = (180-light)/180
+ else:
+ lumratio = light/180
+
+ if ( not smoothed and i) :
+ #A VOIR
+ #OBSCURE
+ colors.extend((colors[-2], colors[-1]))
+
+ if (basiccolor) :
+ # création des couleurs dérivées
+ shade = lightingcolor(basiccolor, lumratio)
+ color0 = "%s;%s"% (shade, reliefalphas[0])
+ color1 = "%s;%s"% (shade, reliefalphas[1])
+ colors.extend((color0, color1))
+
+ else :
+ c = (255*lumratio)
+ color0 = hexargbcolor(c, c, c, reliefalphas[0])
+ color1 = hexargbcolor(c, c, c, reliefalphas[1])
+ colors.extend((color0, color1))
+
+
+ if (i == (numfaces - 2)) :
+ if (closed) :
+ next = coords[0]
+ else:
+ next = (coords[i+1][0] + (coords[i+1][0] - pt[0]),
+ coords[i+1][1] + (coords[i+1][1] - pt[1]))
+ else :
+ next = coords[i+2]
+
+ previous = coords[i]
+
+ if (closed) :
+ pts.extend((pts[0], pts[1], pts[2], pts[3]))
+ colors.extend((colors[0], colors[1]))
+
+ if (not smoothed) :
+ pts.extend((pts[0], pts[1], pts[2], pts[3]))
+ colors.extend((colors[0], colors[1]))
+
+ return (pts, colors)
+
+
+def graphicitem_shadow(widget, item, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::graphicitem_shadow
+ # Création d'une ombre portée à l'item
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant widget Zinc
+ # item : <tagOrId> identifiant item Zinc
+ # options : <hash> table d'options
+ # -opacity : <percent> opacité de l'ombre (défaut 50)
+ # -filled : <boolean> remplissage totale de l'ombre (hors bordure) (defaut 1)
+ # -lightangle : <angle> angle d'éclairage (défaut valeur générale widget)
+ # -distance : <dimension> distance de projection de l'ombre en pixel
+ # -enlarging : <dimension> grossi de l'ombre portée en pixels (defaut 0)
+ # -width : <dimension> taille de diffusion/diffraction (défaut 4)
+ # -color : <color> couleur de l'ombre portée (défaut black)
+ #---------------------------------------------------------------------------
+ """
+ items = []
+
+ # relief d'une liste d'items -> appel récursif
+ if (type(item) in (types.TupleType, types.ListType)) :
+ for part in item :
+ items.append(graphicitem_shadow(widget, part, **options))
+ return items
+
+ else :
+
+ itemtype = widget.type(item)
+
+ if not itemtype :
+ raise ValueError("Not a valid Item Id %s"%item)
+
+ # création d'un groupe à l'ombre portée
+ if (options.has_key('parentgroup')) :
+ parentgroup = options['parentgroup']
+ else:
+ parentgroup = widget.group(item)
+ if (options.has_key('priority')) :
+ priority = options['priority']
+ else:
+ priority = widget.itemcget(item, 'priority')-1
+ priority = max(0, priority)
+
+ shadow = widget.add('group', parentgroup, priority = priority)
+
+ if (itemtype == 'text') :
+ if (options.has_key('opacity')) :
+ opacity = options['opacity']
+ else:
+ opacity = 50
+ if (options['color']) :
+ color = options['color']
+ else:
+ color = '#000000'
+
+ clone = widget.clone(item, color = "%s;%s"% (color, opacity))
+ widget.chggroup(clone, shadow)
+
+ else :
+
+ # création des items (de dessin) de l'ombre
+ if ( options.has_key('filled')) :
+ filled = options['filled']
+ else:
+ filled = 1
+
+ # coords transformés (polyline) de l'item
+ for coords in zincitem_2_curvecoords(widget,
+ item,
+ linear = 1,
+ realcoords = 1) :
+ (t_pts, i_pts, colors) = polyline_shadow_params( coords,
+ **options)
+
+ # option filled : remplissage hors bordure
+ # de l'ombre portée (item curve)
+ if (filled) :
+ if (len(items)) :
+ widget.contour(items[0], 'add', 0, i_pts)
+
+ else :
+ items.append( widget.add('curve', shadow, i_pts,
+ linewidth = 0,
+ filled = 1,
+ fillcolor = colors[0],
+ ))
+
+ # bordure de diffusion de l'ombre (item triangles)
+ items.append( widget.add('triangles', shadow, t_pts,
+ colors = colors))
+
+
+ # positionnement de l'ombre portée
+ if (options.has_key('distance')) :
+ distance = options['distance']
+ else:
+ distance = 10
+ if (options.has_key('lightangle')) :
+ lightangle = options['lightangle']
+ else:
+ lightangle = widget.cget('lightangle')
+
+ (delta_x, delta_y) = rad_point((0, 0),
+ distance,
+ lightangle+180)
+ widget.translate(shadow, delta_x, -delta_y)
+
+ return shadow
+
+
+def polyline_shadow_params(coords, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::polyline_shadow_params
+ # retourne les listes des points et de couleurs nécessaires à la
+ # construction des items triangles (bordure externe) et curve
+ # (remplissage interne) de l'ombre portée
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # coords : coordonnées
+ # options : <hash> table d'options
+ # -opacity : <percent> opacité de l'ombre (défaut 50)
+ # -lightangle : <angle> angle d'éclairage (défaut valeur générale widget)
+ # -distance : <dimension> distance de projection de l'ombre en pixel
+ # (défaut 10)
+ # -enlarging : <dimension> grossi de l'ombre portée en pixels (defaut 2)
+ # -width : <dimension> taille de diffusion/diffraction
+ # (défaut distance -2)
+ # -color : <color> couleur de l'ombre portée (défaut black)
+ #---------------------------------------------------------------------------
+ """
+ if (options.has_key('distance')) :
+ distance = options['distance']
+ else:
+ distance = 10
+ if (options.has_key('width')) :
+ width = options['width']
+ else:
+ width = distance-2
+ if (options.has_key('opacity')) :
+ opacity = options['opacity']
+ else:
+ opacity = 50
+ if (options.has_key('color')) :
+ color = options['color']
+ else:
+ color ='#000000'
+ if (options.has_key('enlarging')) :
+ enlarging = options['enlarging']
+ else :
+ enlarging = 2
+
+ if (enlarging) :
+ coords = shiftpath_coords(coords,
+ width = enlarging,
+ closed = 1,
+ shifting = 'out')
+
+ numfaces = len(coords)
+ previous = coords[numfaces - 1]
+ next = coords[1]
+
+ t_pts = []
+ i_pts = []
+ colors = []
+ (color0, color1) = ("%s;%s"% (color, opacity), "%s;0"% color)
+
+ for i in xrange(0, numfaces):
+ pt = coords[i]
+
+ #A VOIR
+ #Je ne vois pas quand cela peut arriver
+ if (not previous) :
+ # extrémité de curve sans raccord -> angle plat
+ previous = (pt[0] + (pt[0] - next[0]), pt[1] + (pt[1] - next[1]))
+
+ (angle, bisecangle) = vertex_angle(previous, pt, next)
+
+ # distance au centre du cercle inscrit : rayon/sinus demi-angle
+ asin = sin(radians(angle/2))
+ if (asin) :
+ delta = abs(width / asin)
+ else :
+ delta = width
+ decal = 90
+
+ shift_pt = rad_point(pt, delta, bisecangle+decal)
+ i_pts.append(shift_pt)
+ t_pts.append(shift_pt)
+ t_pts.append(pt)
+
+ colors.append(color0)
+ colors.append(color1)
+ if (i == numfaces - 2) :
+ next = coords[0]
+ else :
+ next = coords[i+2]
+
+ previous = coords[i]
+
+ # fermeture
+ t_pts.extend((t_pts[0], t_pts[1], t_pts[2], t_pts[3]))
+ i_pts.extend((t_pts[0], t_pts[1]))
+ colors.extend((color0, color1, color0, color1))
+
+ return (t_pts, i_pts, colors)
+
+
+
+
+
+#Local Variables:
+#mode : python
+#tab-width: 4
+#end:
diff --git a/Python/build/lib.linux-x86_64-2.7/Zinc/pictorial.py b/Python/build/lib.linux-x86_64-2.7/Zinc/pictorial.py
new file mode 100755
index 0000000..1599935
--- /dev/null
+++ b/Python/build/lib.linux-x86_64-2.7/Zinc/pictorial.py
@@ -0,0 +1,766 @@
+# -*- coding: iso-8859-1 -*-
+# Pictorial Functions :
+# ----------------------
+# set_gradients
+# get_pattern
+# get_texture
+# get_image
+# init_pixmaps
+# zincitem_predominantcolor
+# zncolor_to_rgb
+# hexargbcolor
+# create_graduate
+# path_graduate
+# mediancolor
+# lightingcolor
+# rgb_to_lch
+# lch_to_rgb
+# rgb_to_hls
+# hls_to_rgb
+
+import PIL.Image, PIL.ImageTk
+import re
+from math import pi, radians, atan2, sqrt, sin, cos
+
+# initialisation et partage de ressources couleurs et images
+textures = {}
+IMAGES = {}
+bitmaps = {}
+AVERAGE_COLOR = '#777777'
+
+
+_GRADIENTS = []
+
+# constante white point (conversion couleur espace CIE XYZ)
+(Xw, Yw, Zw) = (95.047, 100.0, 108.883)
+
+def set_gradients(zinc, **grads):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::set_gradients
+ # création de gradient nommés Zinc
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant du widget zinc
+ # **grads : <dictionnaire> de définition de couleurs zinc
+ #---------------------------------------------------------------------------
+ """
+ global _GRADIENTS
+ if (not _GRADIENTS):
+ _GRADIENTS = []
+ for (name, gradient) in grads.items():
+ zinc.gname(gradient, name)
+ _GRADIENTS.append(name)
+
+def rgb_dec2hex(rgb):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::rgb_dec2hex
+ # conversion d'une couleur RGB (255,255,255) au format Zinc '#ffffff'
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # rgb : <rgbColorList> liste de couleurs au format RGB
+ #---------------------------------------------------------------------------
+ """
+ return "#%04x%04x%04x"% rgb
+
+def path_graduate(zinc, numcolors, style):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::path_graduate
+ # création d'un jeu de couleurs dégradées pour item pathline
+ #---------------------------------------------------------------------------
+ """
+ typ = style['type']
+ if (typ == 'linear'):
+ return create_graduate(numcolors, style['colors'], 2)
+ elif (typ == 'double'):
+ colors1 = create_graduate(numcolors/2+1,
+ style['colors'][0])
+ colors2 = create_graduate(numcolors/2+1,
+ style['colors'][1])
+ colors = []
+ for i in xrange(numcolors+1):
+ colors.extend([colors1[i], colors2[i]])
+ return colors
+ elif (typ == 'transversal'):
+ (c1, c2) = style['colors']
+ colors = [c1, c2]
+ for i in xrange(numcolors):
+ colors.extend([c1, c2])
+
+ return colors
+
+def create_graduate(totalsteps, refcolors, repeat = 1):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::create_graduate
+ # création d'un jeu de couleurs intermédiaires (dégradé) entre n couleurs
+ #---------------------------------------------------------------------------
+ """
+ colors = []
+
+ numgraduates = len(refcolors) - 1
+ if (numgraduates < 1):
+ raise ValueError("Le degradé necessite\
+ au moins 2 couleurs de référence...")
+ steps = None
+ if (numgraduates > 1):
+ steps = totalsteps/(numgraduates - 1)
+ else:
+ steps = totalsteps
+
+ for c in xrange(numgraduates):
+ (c1, c2) = (refcolors[c], refcolors[c + 1])
+
+ for i in xrange(steps):
+ color = mediancolor(c1, c2, i / (steps - 1))
+ for it in xrange(repeat):
+ colors.append(color)
+
+ if (c < numgraduates - 1):
+ for k in xrange(repeat):
+ colors.pop()
+
+ return colors
+
+def lightingcolor (color, new_l) :
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::lightingcolor
+ # modification d'une couleur par sa composante luminosité
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # color : <color> couleur au format zinc
+ # new_l : <pourcent> (de 0 à 1) nouvelle valeur de luminosité
+ #---------------------------------------------------------------------------
+ """
+ (h, l, s) = 0, 0, 0
+ rgb = hexa2rgb(color)
+ h, l, s = rgb_to_hls(rgb)
+ new_l = min(new_l, 1)
+ (n_r, n_g, n_b) = hls_to_rgb(h, new_l, s)
+ return hexargbcolor(n_r*255, n_g*255, n_b*255)
+
+
+def get_predominantcolor(colors):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::get_predominantcolor
+ # donne la couleur dominante
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # colors : <color>* liste de couleurs au format zinc
+ #---------------------------------------------------------------------------
+ """
+ (rs, gs, bs, as_, numcolors) = (0, 0, 0, 0, 0)
+ for color in colors :
+ (r, g, b, a) = zncolor_to_rgb(color)
+ rs += r
+ gs += g
+ bs += b
+ as_ += a
+ numcolors += 1
+
+ new_r = int(rs/numcolors)
+ new_g = int(gs/numcolors)
+ new_b = int(bs/numcolors)
+ new_a = int(as_/numcolors)
+
+ newcolor = hexargbcolor(new_r, new_g, new_b, new_a)
+ return newcolor
+
+def zincitem_predominantcolor(widget, item):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::zincitem_predominantcolor
+ # retourne la couleur dominante d'un item ('barycentre' gradiant fillcolor)
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant du widget zinc
+ # item : <tagOrId> identifiant de l'item zinc
+ #---------------------------------------------------------------------------
+ """
+ typ = widget.type(item)
+ if not typ :
+ raise ValueError("Not a Valid Item %s" % item)
+ if (typ == 'text' or typ == 'icon') :
+ return widget.itemcget(item, 'color')
+
+ elif (typ == 'triangles' or
+ typ == 'rectangle' or
+ typ == 'arc' or
+ typ == 'curve') :
+
+ colors = []
+
+ if (typ == 'triangles') :
+ colors = widget.itemcget(item, 'colors')
+ else :
+ grad = widget.itemcget(item, 'fillcolor')
+ regexp = re.compile(
+ "^=(?P<class>\w+)(?P<params>[^|]+)\|(?P<colorparts>.*)$")
+ res = regexp.match(grad)
+ if (res is None):
+ #couleur simple
+ return grad
+ else:
+ #Gradient
+ colorspart = res.group('colorparts').split("|")
+ regexp_color = re.compile("^(?P<color>^\S+).*")
+ for colorpart in colorspart:
+ res = regexp_color.match(colorpart)
+ if res:
+ colors.append(res.group('color'))
+ else :
+ raise ValueError("Impossible case!!")
+ return get_predominantcolor(colors)
+ else :
+ return AVERAGE_COLOR
+
+def mediancolor (color1, color2, rate) :
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::mediancolor
+ # calcul d'une couleur intermédiaire défini par un ratio ($rate)
+ # entre 2 couleurs
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # color1 : <color> première couleur zinc
+ # color2 : <color> seconde couleur zinc
+ # rate : <pourcent> (de 0 à 1) position de la couleur intermédiaire
+ #---------------------------------------------------------------------------
+ """
+ if (rate > 1):
+ rate = 1
+ if (rate < 0):
+ rate = 0
+
+ (r0, g0, b0, a0) = zncolor_to_rgb(color1)
+ (r1, g1, b1, a1) = zncolor_to_rgb(color2)
+
+ r = r0 + int((r1 - r0) * rate)
+ g = g0 + int((g1 - g0) * rate)
+ b = b0 + int((b1 - b0) * rate)
+ a = a0 + int((a1 - a0) * rate)
+
+ return hexargbcolor(r, g, b, a)
+
+
+def zncolor_to_rgb (zncolor):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::zncolor_to_rgb
+ # conversion d'une couleur Zinc au format RGBA (255,255,255,100)
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # zncolor : <color> couleur au format hexa zinc (#ffffff ou #ffffffffffff)
+ #---------------------------------------------------------------------------
+ """
+ #Recherche du format d'entrée
+ # ffffff ou ffffffffffff avec ou sans alpha
+ #test présence alpha
+ res = []
+ res.append(
+ re.match(
+ "^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2});(?P<alpha>\d{1,3})$"
+ ,zncolor))
+ res.append(
+ re.match(
+ "^#([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4});(?P<alpha>\d{1,3})$"
+ ,zncolor))
+ #Pas de alpha
+ res.append(re.match("^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$"
+ ,zncolor))
+ res.append(re.match("^#([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})$"
+ ,zncolor))
+ res.sort()
+ resultat = res.pop()
+ if res is None:
+ raise ValueError("Not a valid zinc color")
+ alpha = 100
+ res = resultat.groupdict()
+ if res.has_key('alpha'):
+ alpha = int(res['alpha'])
+ else:
+ alpha = 100
+
+ R = int(resultat.group(1), 16)
+ G = int(resultat.group(2), 16)
+ B = int(resultat.group(3), 16)
+
+ return (R, G, B, alpha)
+
+def rgb_to_lch(r, g, b) :
+ """
+ #---------------------------------------------------------------------------
+ # ALGORYTHMES DE CONVERSION ENTRE ESPACES DE COULEURS
+ #---------------------------------------------------------------------------
+ #---------------------------------------------------------------------------
+ # Graphics::rgb_to_lch
+ # Algorythme de conversion RGB -> CIE LCH°
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # r : <pourcent> (de 0 à 1) valeur de la composante rouge de la couleur RGB
+ # g : <pourcent> (de 0 à 1) valeur de la composante verte de la couleur RGB
+ # b : <pourcent> (de 0 à 1) valeur de la composante bleue de la couleur RGB
+ #---------------------------------------------------------------------------
+ """
+ # Conversion RGBtoXYZ
+ gamma = 2.4
+ rgblimit = 0.03928
+
+ if (r > rgblimit):
+ r = ((r + 0.055)/1.055)**gamma
+ else :
+ r = r / 12.92
+
+ if (g > rgblimit) :
+ g = ((g + 0.055)/1.055)**gamma
+ else:
+ g = g / 12.92
+
+ if (b > rgblimit) :
+ b = ((b + 0.055)/1.055)**gamma
+ else:
+ b = b / 12.92
+
+ r *= 100
+ g *= 100
+ b *= 100
+
+ X = (0.4124 * r) + (0.3576 * g) + (0.1805 * b)
+ Y = (0.2126 * r) + (0.7152 * g) + (0.0722 * b)
+ Z = (0.0193 * r) + (0.1192 * g) + (0.9505 * b)
+
+ # Conversion XYZtoLab
+ gamma = 1/3
+ (L, A, B) = 0, 0, 0
+
+ if (Y == 0) :
+ (L, A, B) = (0, 0, 0)
+ else :
+ #Utilisation des constantes white point (variables globale)
+ (Xs, Ys, Zs) = (X/Xw, Y/Yw, Z/Zw)
+
+
+ if (Xs > 0.008856) :
+ Xs = Xs**gamma
+ else :
+ Xs = (7.787 * Xs) + (16/116)
+
+ if (Ys > 0.008856) :
+ Ys = Ys**gamma
+ else :
+ Ys = (7.787 * Ys) + (16/116)
+
+ if (Zs > 0.008856) :
+ Zs = Zs**gamma
+ else :
+ Zs = (7.787 * Zs) + (16/116)
+
+ L = (116.0 * Ys) - 16.0
+
+ A = 500 * (Xs - Ys)
+ B = 200 * (Ys - Zs)
+
+ # conversion LabtoLCH
+ (C, H) = 0, 0
+
+
+ if (A == 0) :
+ H = 0
+ else :
+ H = atan2(B, A)
+
+ if (H > 0) :
+ H = (H / pi) * 180
+
+ else :
+ H = 360 - ( abs(H) / pi) * 180
+
+
+
+ C = sqrt(A**2 + B**2)
+
+ return (L, C, H)
+
+def lch_to_rgb (L, C, H) :
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::lch_to_rgb
+ # Algorythme de conversion CIE L*CH -> RGB
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # L : <pourcent> (de 0 à 1) valeur de la composante luminosité
+ # de la couleur CIE LCH
+ # C : <pourcent> (de 0 à 1) valeur de la composante saturation
+ # de la couleur CIE LCH
+ # H : <pourcent> (de 0 à 1) valeur de la composante teinte
+ # de la couleur CIE LCH
+ #---------------------------------------------------------------------------
+ """
+ (a, b) = 0, 0
+
+ # Conversion LCHtoLab
+ a = cos( radians(H)) * C
+ b = sin( radians(H)) * C
+
+ # Conversion LabtoXYZ
+ gamma = 3
+ (X, Y, Z) = 0, 0, 0
+
+ Ys = (L + 16.0) / 116.0
+ Xs = (a / 500) + Ys
+ Zs = Ys - (b / 200)
+
+ if ((Ys**gamma) > 0.008856) :
+ Ys = Ys**gamma
+ else :
+ Ys = (Ys - 16 / 116) / 7.787
+
+ if ((Xs**gamma) > 0.008856) :
+ Xs = Xs**gamma
+ else :
+ Xs = (Xs - 16 / 116) / 7.787
+
+ if ((Zs**gamma) > 0.008856) :
+ Zs = Zs**gamma
+ else :
+ Zs = (Zs - 16 / 116) / 7.787
+
+
+ X = Xw * Xs
+ Y = Yw * Ys
+ Z = Zw * Zs
+
+ # Conversion XYZtoRGB
+ gamma = 1/2.4
+ rgblimit = 0.00304
+ (R, G, B) = (0, 0, 0)
+
+ X /= 100
+ Y /= 100
+ Z /= 100
+
+ R = (3.2410 * X) + (-1.5374 * Y) + (-0.4986 * Z)
+ G = (-0.9692 * X) + (1.8760 * Y) + (0.0416 * Z)
+ B = (0.0556 * X) + (-0.2040 * Y) + (1.0570 * Z)
+
+ if (R > rgblimit) :
+ R = (1.055 * (R**gamma)) - 0.055
+ else :
+ R = (12.92 * R)
+
+ if (G > rgblimit) :
+ G = (1.055 * (G**gamma)) - 0.055
+ else :
+ G = (12.92 * G)
+
+ if (B > rgblimit) :
+ B = (1.055 * (B**gamma)) - 0.055
+ else :
+ B = (12.92 * B)
+
+ if (R < 0) :
+ R = 0
+ elif (R > 1.0) :
+ R = 1.0
+ else :
+ R = _trunc(R, 5)
+
+ if (G < 0) :
+ G = 0
+ elif (G > 1.0) :
+ G = 1.0
+ else :
+ G = _trunc(G, 5)
+
+ if (B < 0) :
+ B = 0
+ elif (B > 1.0) :
+ B = 1.0
+ else :
+ B = _trunc(B, 5)
+
+ return (R, G, B)
+
+def rgb_to_hls(r, g, b):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::rgb_to_hls
+ # Algorythme de conversion RGB -> HLS
+ #---------------------------------------------------------------------------
+ # r : <pourcent> (de 0 à 1) valeur de la composante rouge de la couleur RGB
+ # g : <pourcent> (de 0 à 1) valeur de la composante verte de la couleur RGB
+ # b : <pourcent> (de 0 à 1) valeur de la composante bleue de la couleur RGB
+ #---------------------------------------------------------------------------
+ """
+ H, L, S = 0, 0, 0
+ minv, maxv, diffv = 0, 0, 0
+ maxv = max(r, g, b)
+ minv = min(r, g, b)
+
+ # calcul de la luminosité
+ L = (maxv + minv) / 2
+
+ # calcul de la saturation
+ if (maxv == minv) :
+ # couleur a-chromatique (gris) r = g = b
+ S = 0
+ H = None
+ return [H, L, S]
+
+ # couleurs "Chromatiques" --------------------
+
+ # calcul de la saturation
+ if (L <= 0.5) :
+ S = (maxv - minv) / (maxv + minv)
+
+ else :
+ S = (maxv - minv) / (2 - maxv - minv)
+
+ # calcul de la teinte
+ diffv = maxv - minv
+
+ if (r == maxv) :
+ # couleur entre jaune et magenta
+ H = (g - b) / diffv
+
+ elif (g == maxv) :
+ # couleur entre cyan et jaune
+ H = 2 + (b - r) / diffv
+
+ elif (b == maxv) :
+ # couleur entre magenta et cyan
+ H = 4 + (r - g) / diffv
+
+ # Conversion en degrés
+ H *= 60
+
+ # pour éviter une valeur négative
+ if (H < 0) :
+ H += 360
+
+ return [H, L, S]
+
+def hls_to_rgb (H, L, S):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::hls_to_rgb
+ # Algorythme de conversion HLS -> RGB
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # H : <pourcent>(de 0 à 1) valeur de la composante teinte de la couleur HLS
+ # L : <pourcent>(de 0 à 1) valeur de la composante luminosité de la
+ # couleur HLS
+ # S : <pourcent>(de 0 à 1) valeur de la composante saturation
+ # de la couleur HLS
+ #---------------------------------------------------------------------------
+ """
+ (R, G, B) = 0, 0, 0
+ (p1, p2) = 0, 0
+
+
+ if (L <= 0.5) :
+ p2 = L + (L * S)
+
+ else :
+ p2 = L + S - (L * S)
+
+ p1 = 2.0 * L - p2
+
+ if (S == 0) :
+ # couleur a-chromatique (gris)
+ # R = G = B = L
+ R = L
+ G = L
+ B = L
+
+ else :
+ # couleurs "Chromatiques"
+ R = hls_value(p1, p2, H + 120)
+ G = hls_value(p1, p2, H)
+ B = hls_value(p1, p2, H - 120)
+
+ return [R, G, B]
+
+def hls_value(q1, q2, hue):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::hls_value (sous fonction interne hls_to_rgb)
+ #---------------------------------------------------------------------------
+ """
+ value = None
+
+ hue = hue % 360
+
+ if (hue < 60) :
+ value = q1 + (q2 - q1) * hue / 60
+
+ elif (hue < 180) :
+ value = q2
+
+ elif (hue < 240) :
+ value = q1 + (q2 - q1) * (240 - hue) / 60
+
+ else :
+ value = q1
+
+ return value
+
+def hexargbcolor(r, g, b, a = None):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::hexargbcolor
+ # conversion d'une couleur RGB (255,255,255) au format Zinc '#ffffff'
+ #---------------------------------------------------------------------------
+ """
+ hexacolor = "#%02x%02x%02x"% (r, g, b)
+ if ( a is not None ):
+ hexacolor = "%s;%d"% (hexacolor, a)
+ return hexacolor
+
+
+
+def hexa2rgb(hexastr):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::hexa2rgb
+ # conversion d'une couleur au format Zinc '#ffffff' en RGB (255,255,255)
+ #---------------------------------------------------------------------------
+ """
+ r, g, b = 0, 0, 0
+ regex = re.compile("^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$")
+ res = regex.match(hexastr)
+ if res is not None :
+ r = int(res.group(1), 16)
+ g = int(res.group(2), 16)
+ b = int(res.group(3), 16)
+ return (r/255, g/255, b/255)
+ else :
+ raise ValueError("Not a hexa color")
+
+def get_pattern (filename, **options):
+ """
+ #---------------------------------------------------------------------------
+ # RESOURCES GRAPHIQUES PATTERNS, TEXTURES, IMAGES, GRADIENTS, COULEURS...
+ #---------------------------------------------------------------------------
+ #---------------------------------------------------------------------------
+ # Graphics::get_pattern
+ # retourne la ressource bitmap en l'initialisant si première utilisation
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # filename : nom du fichier bitmap pattern
+ # options
+ # -storage : <hastable> référence de la table de stockage de patterns
+ #---------------------------------------------------------------------------
+ """
+ if (options.has_key('storage')):
+ table = options['storage']
+ else :
+ table = bitmaps
+ if (not table.has_key(filename)) :
+ bitmap = "@%s"% (find_inc(filename))
+ table[filename] = bitmap
+ return table[filename]
+
+def get_texture(widget, filename, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::get_texture
+ # retourne l'image de texture en l'initialisant si première utilisation
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant du widget zinc
+ # filename : nom du fichier texture
+ # options
+ # -storage : <hastable> référence de la table de stockage de textures
+ #---------------------------------------------------------------------------
+ """
+ if (options.has_key('storage')):
+ table = options['storage']
+ else :
+ table = textures
+ return get_image(widget, filename, storage = table)
+
+class FileNotFound (Exception):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::FileNotFound
+ # Classe d'exception levée lorsqu'un fichier n'est pas trouvé
+ # paramètres :
+ # filename : nom du fichier
+ #---------------------------------------------------------------------------
+ """
+ def __init__(self, filename):
+ Exception.__init__(self, "File %s not Found"%(filename))
+
+def find_inc(name):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::find_inc
+ # recherche le fichier dans les répertoires de PYTHONPATH
+ #---------------------------------------------------------------------------
+ """
+ import sys
+ import os.path
+ for path in sys.path:
+ tfile = os.path.join(path, name)
+ if (os.path.isfile(tfile)):
+ return tfile
+ raise FileNotFound(name)
+
+
+def get_image(zinc, filename, storage = {}):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::get_image
+ # retourne la ressource image en l'initialisant si première utilisation
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant du widget zinc
+ # filename : nom du fichier image
+ # options
+ # storage : <hastable> référence de la table de stockage d'images
+ #---------------------------------------------------------------------------
+ """
+ if (not storage.has_key(filename)):
+ im = PIL.Image.open(find_inc(filename))
+ #Cela marche uniquement si Tkinter.Tk a une instance
+ image = PIL.ImageTk.PhotoImage(im)
+ storage[filename] = image
+ return storage[filename]
+
+def init_pixmaps(widget, *pixfiles, **options):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::init_pixmaps
+ # initialise une liste de fichier image
+ #---------------------------------------------------------------------------
+ # paramètres :
+ # widget : <widget> identifiant du widget zinc
+ # filenames : <filenameList> list des noms des fichier image
+ # options
+ # storage : <hastable> référence de la table de stockage d'images
+ #---------------------------------------------------------------------------
+ """
+ imgs = []
+ for pixfile in pixfiles:
+ imgs.append(get_image(widget, pixfile, **options))
+ return imgs
+
+def _trunc(f, n):
+ """
+ #---------------------------------------------------------------------------
+ # Graphics::_trunc
+ # fonction interne de troncature des nombres: n = position décimale
+ #---------------------------------------------------------------------------
+ """
+ import fpformat
+ return fpformat.fix(f, n)
+
+#Local Variables:
+#mode : python
+#tab-width: 4
+#end:
diff --git a/Python/demos/testGraphics.py b/Python/demos/testGraphics.py
index 5f22f9f..0b27b34 100644
--- a/Python/demos/testGraphics.py
+++ b/Python/demos/testGraphics.py
@@ -7,7 +7,7 @@
#
# Authors: Jean-Luc Vinot <vinot@cena.fr> Guilaume Vidon <vidon@ath.cena.fr>
#
-# $Id$
+# $Id: testGraphics.py 1698 2005-06-13 00:26:40Z vidon $
#-----------------------------------------------------------------------------------
import sys
diff --git a/Python/library/Zinc.py b/Python/library/Zinc.py
index f55aa56..d5a276d 100644
--- a/Python/library/Zinc.py
+++ b/Python/library/Zinc.py
@@ -6,7 +6,7 @@
# Authors : Frederic Lepied, Patrick Lecoanet
# Created Date : Thu Jul 22 09:36:04 1999
#
-# $Id$
+# $Id: Zinc.py 1908 2008-09-15 09:38:54Z lecoanet $
#
#
# Copyright (c) 1999 CENA --
@@ -16,8 +16,8 @@
#
#
-__version__ = "$Revision$"
-__revision__ = "$Revision$"
+__version__ = "$Revision: 1908 $"
+__revision__ = "$Revision: 1908 $"
from Tkinter import *
import new
diff --git a/Python/library/graphics.py b/Python/library/graphics.py
index 20f68c7..5277e5c 100644
--- a/Python/library/graphics.py
+++ b/Python/library/graphics.py
@@ -43,7 +43,7 @@
# Authors: Jean-Luc Vinot <vinot@cena.fr>
# PM2PY: Guillaume Vidon <vidon@ath.cena.fr>
#
-# $Id$
+# $Id: graphics.py 1697 2005-06-13 00:25:58Z vidon $
#-------------------------------------------------------------------------------
"""
VERSION = "1.0"