[QGIS Commit] r10265 - in trunk/qgis/python/plugins/fTools: . icons icons/default icons/gis tools

svn_qgis at osgeo.org svn_qgis at osgeo.org
Sun Mar 8 20:20:39 EDT 2009


Author: cfarmer
Date: 2009-03-08 20:20:39 -0400 (Sun, 08 Mar 2009)
New Revision: 10265

Added:
   trunk/qgis/python/plugins/fTools/icons/default/delaunay.png
   trunk/qgis/python/plugins/fTools/icons/default/layer_extent.png
   trunk/qgis/python/plugins/fTools/icons/gis/delaunay.png
   trunk/qgis/python/plugins/fTools/icons/gis/layer_extent.png
   trunk/qgis/python/plugins/fTools/tools/voronoi.py
Modified:
   trunk/qgis/python/plugins/fTools/fTools.py
   trunk/qgis/python/plugins/fTools/icons/default/CMakeLists.txt
   trunk/qgis/python/plugins/fTools/icons/gis-0.1.svg
   trunk/qgis/python/plugins/fTools/icons/gis/CMakeLists.txt
   trunk/qgis/python/plugins/fTools/resources.py
   trunk/qgis/python/plugins/fTools/resources.qrc
   trunk/qgis/python/plugins/fTools/tools/CMakeLists.txt
   trunk/qgis/python/plugins/fTools/tools/doGeometry.py
   trunk/qgis/python/plugins/fTools/tools/doRandPoints.py
   trunk/qgis/python/plugins/fTools/tools/ftools_utils.py
Log:
add two new tools - polygon from layer extent - delaunay triangulaltion
changes to menu item - sampling tools -> research tools


Modified: trunk/qgis/python/plugins/fTools/fTools.py
===================================================================
--- trunk/qgis/python/plugins/fTools/fTools.py	2009-03-05 15:06:30 UTC (rev 10264)
+++ trunk/qgis/python/plugins/fTools/fTools.py	2009-03-09 00:20:39 UTC (rev 10265)
@@ -97,8 +97,8 @@
 		self.analysisMenu.addActions( [ self.distMatrix, self.sumLines, self.pointsPoly,
 		self.listUnique, self.compStats, self.nearestNeigh, self.meanCoords, self.intLines ] )
 
-		self.samplingMenu = QMenu( QCoreApplication.translate( "fTools", "&Sampling Tools" ) )
-		self.samplingMenu.setIcon( QIcon( self.getThemeIcon( "sampling.png" ) ) )
+		self.researchMenu = QMenu( QCoreApplication.translate( "fTools", "&Research Tools" ) )
+		self.researchMenu.setIcon( QIcon( self.getThemeIcon( "sampling.png" ) ) )
 		self.randSel = QAction( QIcon( self.getThemeIcon( "random_selection.png" ) ), 
 		QCoreApplication.translate( "fTools", "Random selection" ),self.iface.mainWindow() )
 		self.randSub = QAction( QIcon( self.getThemeIcon( "sub_selection.png" ) ), 
@@ -111,8 +111,10 @@
 		QCoreApplication.translate( "fTools", "Vector grid" ), self.iface.mainWindow() )
 		self.selectLocation = QAction( QIcon( self.getThemeIcon( "select_location.png" ) ), 
 		QCoreApplication.translate( "fTools", "Select by location" ), self.iface.mainWindow() )
-		self.samplingMenu.addActions( [ self.randSel, self.randSub, self.randPoints, 
-		self.regPoints, self.vectGrid, self.selectLocation ] )
+		self.layerExtent = QAction( QIcon( self.getThemeIcon( "layer_extent.png" ) ), 
+		QCoreApplication.translate( "fTools", "Polygon from layer extent" ), self.iface.mainWindow() )
+		self.researchMenu.addActions( [ self.randSel, self.randSub, self.randPoints, 
+		self.regPoints, self.vectGrid, self.selectLocation, self.layerExtent ] )
 
 		self.geoMenu = QMenu( QCoreApplication.translate( "fTools", "&Geoprocessing Tools" ) )
 		self.geoMenu.setIcon( QIcon( self.getThemeIcon( "geoprocessing.png" ) ) )
@@ -143,6 +145,8 @@
 		QCoreApplication.translate( "fTools", "Check geometry validity" ),self.iface.mainWindow() )
 		self.centroids = QAction( QIcon( self.getThemeIcon( "centroids.png") ),  
 		QCoreApplication.translate( "fTools", "Polygon centroids" ),self.iface.mainWindow() )
+		self.delaunay = QAction( QIcon( self.getThemeIcon( "delaunay.png") ),  
+		QCoreApplication.translate( "fTools", "Delaunay triangulation" ),self.iface.mainWindow() )
 		self.extNodes = QAction( QIcon( self.getThemeIcon( "extract_nodes.png") ),  
 		QCoreApplication.translate( "fTools", "Extract nodes" ),self.iface.mainWindow() )
 		self.simplify = QAction( QIcon( self.getThemeIcon( "simplify.png") ),  
@@ -153,8 +157,8 @@
 		QCoreApplication.translate( "fTools", "Singleparts to multipart" ),self.iface.mainWindow() )
 		self.polysToLines = QAction( QIcon( self.getThemeIcon( "to_lines.png") ),  
 		QCoreApplication.translate( "fTools", "Polygons to lines" ),self.iface.mainWindow() )
-		self.conversionMenu.addActions( [ self.checkGeom, self.compGeo, self.centroids, self.simplify, 
-		self.multiToSingle, self.singleToMulti, self.polysToLines, self.extNodes ] )
+		self.conversionMenu.addActions( [ self.checkGeom, self.compGeo, self.centroids, self.delaunay, 
+		self.simplify, self.multiToSingle, self.singleToMulti, self.polysToLines, self.extNodes] )
 
 		self.dataManageMenu = QMenu( QCoreApplication.translate( "fTools", "&Data Management Tools") )
 		self.dataManageMenu.setIcon( QIcon( self.getThemeIcon( "management.png") ) )
@@ -170,21 +174,21 @@
 		QCoreApplication.translate( "fTools", "Split vector layer" ), self.iface.mainWindow() )
 		self.dataManageMenu.addActions( [ self.project, self.define, self.joinAttr, self.spatJoin, self.splitVect ] )
 
-		self.ftools_about = QAction( QIcon( self.getThemeIcon( "ftools_logo.png" ) ), 
-		QCoreApplication.translate( "fTools", "About fTools" ), self.iface.mainWindow() )
+		self.ftools_aboot = QAction( QIcon( self.getThemeIcon( "ftools_logo.png" ) ), 
+		QCoreApplication.translate( "fTools", "fTools About" ), self.iface.mainWindow() )
 
 		self.menu.addMenu( self.analysisMenu )
-		self.menu.addMenu( self.samplingMenu )
+		self.menu.addMenu( self.researchMenu )
 		self.menu.addMenu( self.geoMenu )
 		self.menu.addMenu( self.conversionMenu )
 		self.menu.addMenu( self.dataManageMenu )
 		self.menu.addSeparator()
-		self.menu.addAction( self.ftools_about )
+		self.menu.addAction( self.ftools_aboot )
 
 		menuBar = self.iface.mainWindow().menuBar()
 		actions = menuBar.actions()
-		helpAction = actions[ len( actions ) - 1 ]
-		menuBar.insertMenu( helpAction, self.menu )
+		lastAction = actions[ len( actions ) - 1 ]
+		menuBar.insertMenu( lastAction, self.menu )
         
 		QObject.connect( self.distMatrix, SIGNAL("triggered()"), self.dodistMatrix )
 		QObject.connect( self.sumLines, SIGNAL("triggered()"), self.dosumLines )
@@ -201,6 +205,7 @@
 		QObject.connect( self.regPoints, SIGNAL("triggered()"), self.doregPoints )
 		QObject.connect( self.vectGrid, SIGNAL("triggered()"), self.dovectGrid )
 		QObject.connect( self.selectLocation, SIGNAL("triggered()"), self.doselectLocation )
+		QObject.connect( self.layerExtent, SIGNAL("triggered()"), self.doextent )
 
 		QObject.connect( self.minConvex, SIGNAL("triggered()"), self.dominConvex )
 		QObject.connect( self.intersect, SIGNAL("triggered()"), self.dointersect )
@@ -216,6 +221,7 @@
 		QObject.connect( self.checkGeom, SIGNAL("triggered()"), self.docheckGeom )
 		QObject.connect( self.simplify, SIGNAL("triggered()"), self.dosimplify )
 		QObject.connect( self.centroids, SIGNAL("triggered()"), self.docentroids )
+		QObject.connect( self.delaunay, SIGNAL("triggered()"), self.dodelaunay )
 		QObject.connect( self.polysToLines, SIGNAL("triggered()"), self.dopolysToLines )
 		QObject.connect( self.compGeo, SIGNAL("triggered()"), self.docompGeo )
 		QObject.connect( self.extNodes, SIGNAL("triggered()"), self.doextNodes )
@@ -226,7 +232,7 @@
 		QObject.connect( self.spatJoin, SIGNAL("triggered()"), self.dospatJoin )
 		QObject.connect( self.splitVect, SIGNAL("triggered()"), self.dosplitVect )
 
-		QObject.connect( self.ftools_about, SIGNAL("triggered()"), self.doabout )
+		QObject.connect( self.ftools_aboot, SIGNAL("triggered()"), self.doaboot )
 
 	def unload( self ):
 		pass
@@ -302,6 +308,14 @@
 	def docentroids( self ):
 		d = doGeometry.GeometryDialog( self.iface, 7 )
 		d.exec_()
+		
+	def dodelaunay( self ):
+		d = doGeometry.GeometryDialog( self.iface, 8 )
+		d.exec_()
+		
+	def doextent( self ):
+		d = doGeometry.GeometryDialog( self.iface, 9 )
+		d.exec_()
 
 	def dosumLines(self):
 		d = doSumLines.Dialog(self.iface)
@@ -371,6 +385,6 @@
 		d = doSpatialJoin.Dialog( self.iface )
 		d.exec_()
 
-	def doabout( self ):
+	def doaboot( self ):
 		d = doAbout.Dialog( self.iface )
 		d.exec_()

Modified: trunk/qgis/python/plugins/fTools/icons/default/CMakeLists.txt
===================================================================
--- trunk/qgis/python/plugins/fTools/icons/default/CMakeLists.txt	2009-03-05 15:06:30 UTC (rev 10264)
+++ trunk/qgis/python/plugins/fTools/icons/default/CMakeLists.txt	2009-03-09 00:20:39 UTC (rev 10265)
@@ -43,5 +43,7 @@
 random_selection.png
 ftools_logo.png
 regular_points.png
+delaunay.png
+layer_extent.png
 )
 INSTALL(FILES ${ICON_FILES} DESTINATION ${QGIS_DATA_DIR}/python/plugins/fTools/icons/default)

Added: trunk/qgis/python/plugins/fTools/icons/default/delaunay.png
===================================================================
(Binary files differ)


Property changes on: trunk/qgis/python/plugins/fTools/icons/default/delaunay.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/qgis/python/plugins/fTools/icons/default/layer_extent.png
===================================================================
(Binary files differ)


Property changes on: trunk/qgis/python/plugins/fTools/icons/default/layer_extent.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Modified: trunk/qgis/python/plugins/fTools/icons/gis/CMakeLists.txt
===================================================================
--- trunk/qgis/python/plugins/fTools/icons/gis/CMakeLists.txt	2009-03-05 15:06:30 UTC (rev 10264)
+++ trunk/qgis/python/plugins/fTools/icons/gis/CMakeLists.txt	2009-03-09 00:20:39 UTC (rev 10265)
@@ -43,5 +43,7 @@
 random_selection.png
 ftools_logo.png
 regular_points.png
+delaunay.png
+layer_extent.png
 )
 INSTALL(FILES ${ICON_FILES} DESTINATION ${QGIS_DATA_DIR}/python/plugins/fTools/icons/gis)

Added: trunk/qgis/python/plugins/fTools/icons/gis/delaunay.png
===================================================================
(Binary files differ)


Property changes on: trunk/qgis/python/plugins/fTools/icons/gis/delaunay.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/qgis/python/plugins/fTools/icons/gis/layer_extent.png
===================================================================
(Binary files differ)


Property changes on: trunk/qgis/python/plugins/fTools/icons/gis/layer_extent.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Modified: trunk/qgis/python/plugins/fTools/icons/gis-0.1.svg
===================================================================
--- trunk/qgis/python/plugins/fTools/icons/gis-0.1.svg	2009-03-05 15:06:30 UTC (rev 10264)
+++ trunk/qgis/python/plugins/fTools/icons/gis-0.1.svg	2009-03-09 00:20:39 UTC (rev 10265)
@@ -17,7 +17,7 @@
    version="1.0"
    sodipodi:docname="gis-0.1.svg"
    inkscape:output_extension="org.inkscape.output.svg.inkscape"
-   inkscape:export-filename="/home/cfarmer/.qgis/python/plugins/fTools/gis_icons/matrix.png"
+   inkscape:export-filename="/home/cfarmer/dev/cpp/qgis/python/plugins/fTools/icons/gis/layer_extent.png"
    inkscape:export-xdpi="90"
    inkscape:export-ydpi="90"
    style="display:inline;enable-background:new">
@@ -32,15 +32,15 @@
      inkscape:pageopacity="0"
      inkscape:pageshadow="2"
      inkscape:zoom="16"
-     inkscape:cx="9.0201001"
-     inkscape:cy="8.9456096"
+     inkscape:cx="9.2319959"
+     inkscape:cy="11.794933"
      inkscape:document-units="px"
-     inkscape:current-layer="layer129"
+     inkscape:current-layer="layer155"
      showgrid="true"
      inkscape:window-width="1159"
      inkscape:window-height="700"
      inkscape:window-x="86"
-     inkscape:window-y="72"
+     inkscape:window-y="48"
      inkscape:snap-global="false"
      showguides="true"
      inkscape:guide-bbox="true"
@@ -2370,6 +2370,28 @@
            style="fill:#82a0b4;fill-opacity:1;fill-rule:nonzero;stroke:#3c5a6e;stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:2.4;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
       </g>
     </g>
+    <g
+       inkscape:groupmode="layer"
+       id="layer134"
+       inkscape:label="delaunay"
+       style="display:none"
+       sodipodi:insensitive="true">
+      <path
+         style="fill:none;fill-rule:evenodd;stroke:#3c5a6e;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="M 5.5,15.9375 L 12.5,9.5625 L 0.625,6.125"
+         id="path3778"
+         sodipodi:nodetypes="ccc" />
+      <path
+         style="fill:none;fill-rule:evenodd;stroke:#3c5a6e;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="M 8.0625,0.9375 L 12.4375,9.5 L 17.3125,0.8125"
+         id="path3780"
+         sodipodi:nodetypes="ccc" />
+      <path
+         style="fill:none;fill-rule:evenodd;stroke:#3c5a6e;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+         d="M 23.25,14 L 12.5625,9.4375 L 16.9375,23.0625"
+         id="path3782"
+         sodipodi:nodetypes="ccc" />
+    </g>
   </g>
   <g
      style="display:none"
@@ -6099,26 +6121,35 @@
        inkscape:groupmode="layer"
        id="layer129"
        inkscape:label="matrix"
-       style="display:inline">
-      <g
-         id="g4571">
-        <path
-           id="path3756"
-           d="M 5.499146,0.50519709 L 5.499146,23.480886"
-           style="fill:none;fill-rule:evenodd;stroke:#969696;stroke-width:0.97941929px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
-        <path
-           id="path3761"
-           d="M 0.51176719,5.499146 L 23.528038,5.499146"
-           style="fill:none;fill-rule:evenodd;stroke:#969696;stroke-width:0.98028392px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1" />
-        <rect
-           y="6.4966083"
-           x="6.4907565"
-           height="17.023754"
-           width="17.035219"
-           id="rect4569"
-           style="opacity:1;fill:#82a0b4;fill-opacity:0.99215686;fill-rule:nonzero;stroke:#3c5a6e;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.9;stroke-opacity:0.99215686;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
-      </g>
+       style="display:none">
+      <path
+         style="fill:none;fill-rule:evenodd;stroke:#969696;stroke-width:0.97941929px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+         d="M 5.499146,0.50519709 L 5.499146,23.480886"
+         id="path3756" />
+      <path
+         style="fill:none;fill-rule:evenodd;stroke:#969696;stroke-width:0.98028392px;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
+         d="M 0.51176719,5.499146 L 23.528038,5.499146"
+         id="path3761" />
+      <rect
+         style="fill:#82a0b4;fill-opacity:0.99215686;fill-rule:nonzero;stroke:#3c5a6e;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.9;stroke-opacity:0.99215686;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         id="rect4569"
+         width="17.035219"
+         height="17.023754"
+         x="6.4907565"
+         y="6.4966083" />
     </g>
+    <g
+       inkscape:groupmode="layer"
+       id="layer155"
+       inkscape:label="extent">
+      <rect
+         style="fill:#82a0b4;fill-opacity:0.99215686;fill-rule:nonzero;stroke:#3c5a6e;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0.9;stroke-opacity:0.99215686;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+         id="rect3768"
+         width="17.035219"
+         height="17.023754"
+         x="0.5448904"
+         y="0.55062294" />
+    </g>
   </g>
   <g
      style="display:none"
@@ -7097,7 +7128,7 @@
      id="layer39"
      inkscape:groupmode="layer">
     <g
-       style="display:inline"
+       style="display:none"
        inkscape:label="print composer"
        id="layer43"
        inkscape:groupmode="layer">
@@ -8017,7 +8048,7 @@
     </g>
   </g>
   <g
-     style="display:none"
+     style="display:inline"
      inkscape:label="actions"
      id="layer11"
      inkscape:groupmode="layer">
@@ -8267,7 +8298,7 @@
     </g>
     <g
        sodipodi:insensitive="true"
-       style="display:none"
+       style="display:inline"
        inkscape:label="create [yellow]"
        id="layer15"
        inkscape:groupmode="layer">

Modified: trunk/qgis/python/plugins/fTools/resources.py
===================================================================
--- trunk/qgis/python/plugins/fTools/resources.py	2009-03-05 15:06:30 UTC (rev 10264)
+++ trunk/qgis/python/plugins/fTools/resources.py	2009-03-09 00:20:39 UTC (rev 10265)
@@ -2,8 +2,8 @@
 
 # Resource object code
 #
-# Created: Sun Jan 18 22:55:27 2009
-#      by: The Resource Compiler for PyQt (Qt v4.3.4)
+# Created: Mon Mar 9 00:09:47 2009
+#      by: The Resource Compiler for PyQt (Qt v4.4.3)
 #
 # WARNING! All changes made in this file will be lost!
 
@@ -1469,6 +1469,97 @@
 \xf4\x92\xbd\x8d\xb3\x84\x5e\xae\x7c\x20\xbb\x4d\x80\xff\x07\x5c\
 \x69\x9f\x38\xa5\x9a\x04\xb9\x00\x00\x00\x00\x49\x45\x4e\x44\xae\
 \x42\x60\x82\
+\x00\x00\x05\x8c\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x18\x00\x00\x00\x18\x08\x06\x00\x00\x00\xe0\x77\x3d\xf8\
+\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0d\xd7\x00\x00\x0d\xd7\
+\x01\x42\x28\x9b\x78\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
+\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x05\x09\x49\x44\
+\x41\x54\x48\x89\xad\x55\x4b\x4f\x1b\x57\x18\x3d\x33\xe3\x07\xb6\
+\xc7\x24\x36\x7e\x04\x1b\x9c\x50\x0c\x34\x82\x38\x01\x43\x9b\x40\
+\x0a\xca\x2a\x55\x37\x55\xa5\x2a\x51\x21\x54\x5d\x74\x91\x2a\x95\
+\x92\xd0\x4a\x5d\x35\x52\x1b\x55\x95\x5a\x35\x44\x55\x53\x29\x9b\
+\xaa\xa4\x69\x16\x74\x93\xf6\x07\x54\x49\x10\xce\xab\x01\x8c\x91\
+\x2a\xdb\xe0\x07\x60\xde\xb6\xf1\x0b\x7b\xec\x99\x7b\xbb\x48\x4c\
+\x6d\xec\x4a\x59\xf4\xac\x46\xf7\x9e\xef\x9c\xf9\xbe\xfb\xdd\xef\
+\x32\x94\x52\x54\xc3\xc9\xc1\x91\x76\xb9\x8c\xb9\x2b\x11\xe9\x50\
+\x55\x42\x09\x18\x86\x49\x10\x22\xb4\x4c\xfc\xfa\x63\x7c\xef\x9e\
+\xac\x5a\x40\xff\xf0\xe5\x0f\x65\x32\x7c\x6f\x3b\x78\x48\xb9\xb2\
+\x1a\x61\x7b\x7b\x7b\xc1\x32\x4c\x55\x71\xcf\xdc\x1c\x52\xa9\x74\
+\x6d\x36\x87\xf3\x00\xbe\xae\x30\x2f\xcd\xe0\xd4\x99\x0b\x3c\xad\
+\x51\x8e\x29\xe4\xf2\x37\x3b\x3b\xbb\xd4\xbc\x96\xc7\xf4\xcc\x0c\
+\x0c\x06\x03\x1a\x1b\x1a\x2a\xc4\xb7\x13\xdb\x70\xcf\xb8\xe1\x38\
+\xe2\xc0\xd4\xf4\x54\x2c\xad\xca\x1c\xf8\xeb\xe6\xcd\x42\x29\x87\
+\x2d\x7e\xf4\x0d\x5d\x3e\x46\x6b\x94\x7f\x1b\x8d\xc6\xb7\x7a\xfb\
+\xfa\xd4\xbc\x96\x07\x00\xb4\x34\xdb\x11\x0c\x2c\x80\x10\x52\x61\
+\xe0\xf3\x7a\xd1\x62\x6f\x81\x4e\xaf\x83\x4a\xa3\x51\xa8\x53\xaa\
+\xb3\x7b\x39\x2c\x00\x0c\x9c\xbb\x78\x41\xce\x31\xae\x57\x0f\x1f\
+\xb6\x3a\x1c\x8e\x1a\x8e\xe3\x76\x09\xbc\x96\xc7\xbe\x7d\xfb\xb1\
+\xbc\xbc\x5c\x16\xb8\xb6\xb6\x0e\x49\x22\xa8\xb7\x5a\x00\x00\xf6\
+\xa6\x26\x9e\x95\xb3\x57\x2a\x0c\x06\xde\x1f\xb9\xab\x54\xd6\x7c\
+\x7b\xfc\xf8\xeb\x2a\xab\xc5\x52\xb5\xd0\x76\x7b\x33\x42\xc1\x20\
+\x24\xe9\x79\x16\x84\x48\xf0\xfb\x7c\x68\x6b\x6b\x45\x31\xc0\x68\
+\x36\x43\xc6\xc9\x2c\x27\x87\x2e\x9e\x2a\x33\x60\x80\x4e\x51\x92\
+\x54\x33\x6e\x37\x7c\x5e\x2f\x62\xb1\x28\x08\x2d\x2f\x87\x46\xc3\
+\x43\xa7\xd3\x63\x79\x69\x09\x00\x10\x0e\x2f\x82\xd7\xf2\xd0\xeb\
+\xeb\x76\x39\x0c\x80\x43\x4d\x4d\x6a\x99\x8c\xfb\xbc\xcc\x40\x22\
+\xd2\x25\x85\x5c\x9e\x39\xea\x38\x0a\x85\x52\x89\x85\x40\x00\xf7\
+\xef\xdd\x87\x7b\xc6\x8d\x48\x24\x02\x41\x10\x00\x00\xcd\xf6\x66\
+\x84\xc2\x21\x64\xb3\x59\x84\x42\x21\xb4\xb6\xb5\x56\x64\xda\x60\
+\xb1\x32\xa0\xe8\x3d\x39\x7c\xa9\xad\xb8\xc6\x2d\x7a\x1e\x7b\x1b\
+\x3b\x7a\x3e\xaa\x33\x18\x6b\x2d\x16\x0b\xac\x16\x2b\x1a\x1b\x1b\
+\xc0\x71\x1c\xa2\xd1\x18\x7c\x7e\x1f\x56\x57\x57\x21\x11\x09\x84\
+\x52\x04\x03\x01\xd4\xd7\x1f\x80\xa5\xde\x52\x61\xc0\xb2\x2c\xc4\
+\x82\x48\x33\xa9\xf4\xbe\x0f\xde\x39\xfd\x3b\x00\xb0\x94\x52\x4a\
+\x89\x74\x65\x61\x61\x3e\x53\x24\xca\x64\x72\x98\xcd\x66\x74\x74\
+\xb4\x63\xa0\xbf\x1f\xed\xed\xed\x60\x59\x0e\x99\x74\x0a\xf9\x7c\
+\x1e\xc9\x44\x1a\x5b\x5b\x5b\xa8\x76\x49\x0f\x1e\xb4\xc9\x09\x25\
+\xef\x9d\x1a\xfc\xd4\x00\xbc\xe8\xa2\xb4\x3a\x77\x3b\x9d\x4a\xe5\
+\x12\xdb\x89\x8a\x00\x86\x61\x50\x5b\x5b\x0b\x2d\xcf\x83\x50\x0a\
+\x9d\x4e\x07\x96\x63\xe1\xf3\xf9\x31\xe9\x72\x61\x71\x31\x0c\x51\
+\x14\x77\xf9\xca\x9a\x1a\x98\x8c\x26\x42\x38\xe9\x63\xa0\xe4\xa2\
+\xbd\x31\x7c\x71\xa4\xae\xce\xf0\xa5\xb3\xb3\x4b\xb3\xd7\x24\x12\
+\x89\x60\xde\xef\xc7\xb1\xae\x2e\x14\x04\x01\xa1\x70\x18\xdd\xdd\
+\xdd\x88\xc7\xe2\x08\x2f\x2d\x22\x1e\x8b\xa1\xbe\xfe\x00\x1a\x6d\
+\x36\x68\xd4\x1a\xa4\x52\x29\x3c\x79\xfc\x24\xa1\x8e\x8a\xe6\xdd\
+\x51\xa1\x66\x14\x37\xe3\xd1\xd8\x17\x99\x74\x06\x1a\xfe\x5f\x8f\
+\x40\x60\x01\x91\xe5\x15\x74\xbf\xd6\x03\x8d\x5a\x03\x42\x08\x3c\
+\x73\x73\x28\xe4\x0b\xd0\xe9\x75\xd0\xe9\x75\xc8\xe5\x04\x2c\x2f\
+\x2d\xe2\xe9\x93\xa7\xa8\xd5\x6a\x61\xb3\xd9\xa0\xd6\xf2\x5c\x4a\
+\x4a\x0c\x96\x8d\x8a\x81\x73\x23\x57\xcd\x66\xe3\x27\x47\x1c\x0e\
+\x15\xa5\x14\x5e\xaf\x17\xb1\x58\x0c\x4e\xa7\x13\x4a\xa5\x72\x97\
+\x37\xeb\xf1\xa0\x4e\xaf\x87\xd5\x6a\x2d\xcb\x94\x10\x09\x6b\x6b\
+\x6b\x08\x87\x17\x91\xcf\xe7\x21\x4a\x85\x08\x5b\x4a\x28\xe4\x31\
+\xba\xbe\xb1\x89\x6c\x36\x0b\x8f\xc7\x83\x64\x32\x85\x9e\x9e\x9e\
+\x32\x71\x00\x30\x9b\x4c\xd8\x58\x5f\xaf\x38\x2f\x96\xe5\x60\xb1\
+\x58\x71\xe2\xc4\x09\x98\x4d\x26\x02\x70\x5b\x65\x06\xae\xf1\x6b\
+\x31\x30\xf4\xa7\xa9\xa9\x67\x92\x24\x49\x70\x3a\x9d\x90\xcb\xe5\
+\x15\x42\x06\x83\x01\xf1\xed\x44\xd9\xe1\x96\x22\x93\x49\x23\xb2\
+\xb2\x92\xcb\x13\xf2\x2e\xbb\x77\x53\x10\xe9\xd5\x5c\x36\x17\x10\
+\xf3\x85\xb4\x20\xe4\xaa\x0a\x70\x1c\x07\x9d\x5e\x87\xad\xcd\xcd\
+\x8a\x3d\x4a\x28\xdc\xee\xd9\x1d\x42\xf1\x99\xeb\x97\x6b\xf3\x15\
+\x06\x8f\xee\x5c\x5f\x37\x09\x91\xc3\xdb\xe9\xe4\xd5\x87\x0f\x5d\
+\x3b\xc1\x60\x40\xa4\xa4\xb2\xdf\xcd\x26\x33\xd6\x37\x36\x2a\xd6\
+\x03\xc1\x80\x98\xcb\x09\xee\x89\xdb\xa3\x37\x80\x92\x71\x5d\x8a\
+\xf1\xf1\x71\xe9\xc1\xad\xd1\x6f\x28\xc4\x8e\x60\x20\xf4\x68\xd2\
+\xe5\x4a\x27\x92\xc9\x32\x8e\xd1\x68\x40\x34\x1a\xdd\x1d\x80\x00\
+\x90\x4a\x26\x11\x0a\x85\x04\x92\xa7\x67\xe9\x8b\xee\x61\xfe\xeb\
+\xc9\x2c\x45\xff\xe0\xa5\x73\x8c\x8c\xb9\xd1\x60\xb5\x2a\x5a\xec\
+\xad\x35\x9c\xec\xf9\x38\x9f\x7a\xf6\x0c\x0d\x8d\x36\x98\x4c\x46\
+\x10\x42\xe1\x9a\x9c\xdc\xc9\xe6\x73\x17\x1e\xdc\x1a\xfd\xb9\x18\
+\x5b\x35\x83\xbd\x78\x70\xe7\xfa\xed\x1c\x53\x78\x25\xb2\xb2\xf2\
+\xc7\xc4\xc4\xc4\x4e\xb1\xf6\x46\x93\x09\xeb\x2f\xba\x69\xde\xef\
+\x2f\x14\x0a\xf9\x87\xa5\xe2\x2f\x6d\x00\x00\x8f\xc7\x7e\x88\xde\
+\x1b\xbb\x76\x36\x5f\x10\xde\x76\xcf\xce\xae\x4d\xcf\x4c\xef\xe8\
+\xf6\xef\x47\x74\x6b\x13\xf1\xf8\x36\x96\x96\x97\x72\x3b\x05\x69\
+\x68\x6f\xdc\x4b\x95\x68\x2f\x7a\xcf\x8c\xa8\x14\x4a\x7c\x05\x06\
+\xe7\x95\x4a\x85\x4a\x14\x45\x41\x92\xc4\xe1\x7b\xb7\xae\xff\xf6\
+\xbf\x18\x14\xd1\x37\x74\xf9\x98\x5c\xc6\xdc\x61\xc1\x4c\xff\x39\
+\xf6\x5d\xc5\xdf\x03\xc0\x3f\x4b\x1d\x48\xe6\x9d\x4c\x36\xb6\x00\
+\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
 \x00\x00\x05\x60\
 \x89\
 \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -2699,6 +2790,46 @@
 \x06\x2d\xed\xb3\x39\x87\x2c\xa3\x4e\xe4\x50\x7f\xb2\x8d\xee\x40\
 \x10\xc9\x27\x6e\xa3\x3b\x7e\x03\x1c\x81\xee\xcf\x3e\x80\x40\xd3\
 \x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
+\x00\x00\x02\x5f\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x18\x00\x00\x00\x18\x08\x06\x00\x00\x00\xe0\x77\x3d\xf8\
+\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0d\xd7\x00\x00\x0d\xd7\
+\x01\x42\x28\x9b\x78\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
+\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xdc\x49\x44\
+\x41\x54\x48\x89\xed\x95\x31\x6b\x53\x51\x18\x86\x9f\x73\xce\x35\
+\xbd\x1a\x92\x96\xa6\x12\x6f\x17\x35\x01\x69\x4a\x47\x29\x45\x24\
+\x6a\x8a\xfe\x03\x25\x38\xe8\x22\x4e\x52\x08\x41\xff\x84\x38\x89\
+\x4e\x59\xe2\x20\x82\xb3\x60\x14\xdb\x24\x5a\x91\x8c\x0e\x56\x1a\
+\xa8\x0e\xc6\x24\xd0\xd0\xe6\x56\xed\x25\xf4\x9e\xe3\x20\xc6\x62\
+\x09\xd8\x5b\x70\xca\x37\x9e\xef\x3d\xdf\xf3\xbe\xc3\x77\x8e\x38\
+\x7f\x2d\xf7\x5e\x1b\x93\xe4\x00\x25\x10\x9d\x11\x54\xaa\xf4\xe8\
+\xee\xf7\xbf\x7b\x96\xaf\xf5\x54\x3a\x7d\x4e\x29\x29\x03\x03\x5e\
+\x57\xab\xb1\xde\xf6\x8f\x08\xb0\x17\x00\x70\xc8\x52\x48\xa9\x02\
+\x03\x04\x06\x33\xa0\x17\xdc\xf6\x3f\xd6\x10\x30\x04\x0c\x01\xff\
+\x01\x60\x05\xb9\x34\x26\x3e\x90\x34\x05\x39\xca\x2a\x00\x99\x0c\
+\x47\x80\xe6\x72\xf1\x61\x5f\x63\xa0\x26\x24\xf9\x40\x80\xa4\x29\
+\xc8\xf1\x50\x1b\x3b\x72\x1a\xa9\x6c\xa4\xb2\x49\x5d\x7a\xc9\xca\
+\x8b\x8b\x68\xdf\x43\xfb\x1e\xde\x56\x7d\x76\xa7\xd7\xbd\x17\x08\
+\x30\xca\x2a\xe1\x58\x06\x65\x85\xc1\xfc\x79\xe6\x7e\xc3\x10\x02\
+\x15\x8a\xe2\x36\x17\x67\x03\x01\x00\x26\x8e\x5f\x21\x3a\x39\x4f\
+\xe7\xd3\x13\xa2\xf1\x34\x00\x93\x33\xb7\x71\xdb\x55\x62\x27\xb3\
+\xb8\x5f\x5f\xe1\x36\x17\xb1\xa4\x10\xeb\x4b\x4b\xe5\xf1\xfd\x0c\
+\xcf\xcc\x33\xb2\xf1\xe5\x19\xfe\xce\x37\x9c\x99\x3b\x18\xdd\x63\
+\xb3\xf1\x9c\x48\xfc\x2c\xe1\xa3\x73\xb4\x57\xee\xe3\xb6\x2a\x00\
+\x58\x42\x6d\x26\x60\xcc\xde\x67\x80\x0d\x30\xb8\xad\x32\xf1\xa9\
+\x5b\x6c\xb5\xdf\xd0\xfe\xf8\x00\x80\xe8\xb1\x0b\xb8\xad\x72\x5f\
+\x28\x8c\x19\xf4\x55\x0c\xae\xe5\xa2\x30\x20\x98\x48\x5c\x25\x71\
+\xa6\x80\xf6\xb7\xe9\x7c\x7e\x4a\xec\xc4\x65\xa4\x3a\xcc\xda\xdb\
+\x1b\xac\xaf\x3d\x06\x4c\xf0\x3d\x70\x52\x0b\x38\xd3\x39\xea\x95\
+\x2c\xdd\x46\x89\xf8\xa9\x9b\x74\x1b\x25\xea\x95\x2c\xce\x74\x0e\
+\x27\xb5\x70\xb0\x04\x52\xd9\x68\xdd\x03\xa3\x01\x98\xbb\x6e\x78\
+\x57\x14\xbf\x04\x42\x22\x65\x08\xed\x7b\xc1\x12\x18\xa8\x69\xdf\
+\xeb\x0f\xdf\x2b\xd0\x68\xdf\xc3\x40\x2d\x10\x40\x48\xf2\x06\x6a\
+\xbb\xcf\xfa\xee\x77\x99\x10\x92\xfc\x4f\xfd\xc2\xaa\x73\x0e\x12\
+\x9d\x40\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
 \x00\x00\x04\x68\
 \x89\
 \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -5381,6 +5512,97 @@
 \xf4\x92\xbd\x8d\xb3\x84\x5e\xae\x7c\x20\xbb\x4d\x80\xff\x07\x5c\
 \x69\x9f\x38\xa5\x9a\x04\xb9\x00\x00\x00\x00\x49\x45\x4e\x44\xae\
 \x42\x60\x82\
+\x00\x00\x05\x8c\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x18\x00\x00\x00\x18\x08\x06\x00\x00\x00\xe0\x77\x3d\xf8\
+\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0d\xd7\x00\x00\x0d\xd7\
+\x01\x42\x28\x9b\x78\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
+\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x05\x09\x49\x44\
+\x41\x54\x48\x89\xad\x55\x4b\x4f\x1b\x57\x18\x3d\x33\xe3\x07\xb6\
+\xc7\x24\x36\x7e\x04\x1b\x9c\x50\x0c\x34\x82\x38\x01\x43\x9b\x40\
+\x0a\xca\x2a\x55\x37\x55\xa5\x2a\x51\x21\x54\x5d\x74\x91\x2a\x95\
+\x92\xd0\x4a\x5d\x35\x52\x1b\x55\x95\x5a\x35\x44\x55\x53\x29\x9b\
+\xaa\xa4\x69\x16\x74\x93\xf6\x07\x54\x49\x10\xce\xab\x01\x8c\x91\
+\x2a\xdb\xe0\x07\x60\xde\xb6\xf1\x0b\x7b\xec\x99\x7b\xbb\x48\x4c\
+\x6d\xec\x4a\x59\xf4\xac\x46\xf7\x9e\xef\x9c\xf9\xbe\xfb\xdd\xef\
+\x32\x94\x52\x54\xc3\xc9\xc1\x91\x76\xb9\x8c\xb9\x2b\x11\xe9\x50\
+\x55\x42\x09\x18\x86\x49\x10\x22\xb4\x4c\xfc\xfa\x63\x7c\xef\x9e\
+\xac\x5a\x40\xff\xf0\xe5\x0f\x65\x32\x7c\x6f\x3b\x78\x48\xb9\xb2\
+\x1a\x61\x7b\x7b\x7b\xc1\x32\x4c\x55\x71\xcf\xdc\x1c\x52\xa9\x74\
+\x6d\x36\x87\xf3\x00\xbe\xae\x30\x2f\xcd\xe0\xd4\x99\x0b\x3c\xad\
+\x51\x8e\x29\xe4\xf2\x37\x3b\x3b\xbb\xd4\xbc\x96\xc7\xf4\xcc\x0c\
+\x0c\x06\x03\x1a\x1b\x1a\x2a\xc4\xb7\x13\xdb\x70\xcf\xb8\xe1\x38\
+\xe2\xc0\xd4\xf4\x54\x2c\xad\xca\x1c\xf8\xeb\xe6\xcd\x42\x29\x87\
+\x2d\x7e\xf4\x0d\x5d\x3e\x46\x6b\x94\x7f\x1b\x8d\xc6\xb7\x7a\xfb\
+\xfa\xd4\xbc\x96\x07\x00\xb4\x34\xdb\x11\x0c\x2c\x80\x10\x52\x61\
+\xe0\xf3\x7a\xd1\x62\x6f\x81\x4e\xaf\x83\x4a\xa3\x51\xa8\x53\xaa\
+\xb3\x7b\x39\x2c\x00\x0c\x9c\xbb\x78\x41\xce\x31\xae\x57\x0f\x1f\
+\xb6\x3a\x1c\x8e\x1a\x8e\xe3\x76\x09\xbc\x96\xc7\xbe\x7d\xfb\xb1\
+\xbc\xbc\x5c\x16\xb8\xb6\xb6\x0e\x49\x22\xa8\xb7\x5a\x00\x00\xf6\
+\xa6\x26\x9e\x95\xb3\x57\x2a\x0c\x06\xde\x1f\xb9\xab\x54\xd6\x7c\
+\x7b\xfc\xf8\xeb\x2a\xab\xc5\x52\xb5\xd0\x76\x7b\x33\x42\xc1\x20\
+\x24\xe9\x79\x16\x84\x48\xf0\xfb\x7c\x68\x6b\x6b\x45\x31\xc0\x68\
+\x36\x43\xc6\xc9\x2c\x27\x87\x2e\x9e\x2a\x33\x60\x80\x4e\x51\x92\
+\x54\x33\x6e\x37\x7c\x5e\x2f\x62\xb1\x28\x08\x2d\x2f\x87\x46\xc3\
+\x43\xa7\xd3\x63\x79\x69\x09\x00\x10\x0e\x2f\x82\xd7\xf2\xd0\xeb\
+\xeb\x76\x39\x0c\x80\x43\x4d\x4d\x6a\x99\x8c\xfb\xbc\xcc\x40\x22\
+\xd2\x25\x85\x5c\x9e\x39\xea\x38\x0a\x85\x52\x89\x85\x40\x00\xf7\
+\xef\xdd\x87\x7b\xc6\x8d\x48\x24\x02\x41\x10\x00\x00\xcd\xf6\x66\
+\x84\xc2\x21\x64\xb3\x59\x84\x42\x21\xb4\xb6\xb5\x56\x64\xda\x60\
+\xb1\x32\xa0\xe8\x3d\x39\x7c\xa9\xad\xb8\xc6\x2d\x7a\x1e\x7b\x1b\
+\x3b\x7a\x3e\xaa\x33\x18\x6b\x2d\x16\x0b\xac\x16\x2b\x1a\x1b\x1b\
+\xc0\x71\x1c\xa2\xd1\x18\x7c\x7e\x1f\x56\x57\x57\x21\x11\x09\x84\
+\x52\x04\x03\x01\xd4\xd7\x1f\x80\xa5\xde\x52\x61\xc0\xb2\x2c\xc4\
+\x82\x48\x33\xa9\xf4\xbe\x0f\xde\x39\xfd\x3b\x00\xb0\x94\x52\x4a\
+\x89\x74\x65\x61\x61\x3e\x53\x24\xca\x64\x72\x98\xcd\x66\x74\x74\
+\xb4\x63\xa0\xbf\x1f\xed\xed\xed\x60\x59\x0e\x99\x74\x0a\xf9\x7c\
+\x1e\xc9\x44\x1a\x5b\x5b\x5b\xa8\x76\x49\x0f\x1e\xb4\xc9\x09\x25\
+\xef\x9d\x1a\xfc\xd4\x00\xbc\xe8\xa2\xb4\x3a\x77\x3b\x9d\x4a\xe5\
+\x12\xdb\x89\x8a\x00\x86\x61\x50\x5b\x5b\x0b\x2d\xcf\x83\x50\x0a\
+\x9d\x4e\x07\x96\x63\xe1\xf3\xf9\x31\xe9\x72\x61\x71\x31\x0c\x51\
+\x14\x77\xf9\xca\x9a\x1a\x98\x8c\x26\x42\x38\xe9\x63\xa0\xe4\xa2\
+\xbd\x31\x7c\x71\xa4\xae\xce\xf0\xa5\xb3\xb3\x4b\xb3\xd7\x24\x12\
+\x89\x60\xde\xef\xc7\xb1\xae\x2e\x14\x04\x01\xa1\x70\x18\xdd\xdd\
+\xdd\x88\xc7\xe2\x08\x2f\x2d\x22\x1e\x8b\xa1\xbe\xfe\x00\x1a\x6d\
+\x36\x68\xd4\x1a\xa4\x52\x29\x3c\x79\xfc\x24\xa1\x8e\x8a\xe6\xdd\
+\x51\xa1\x66\x14\x37\xe3\xd1\xd8\x17\x99\x74\x06\x1a\xfe\x5f\x8f\
+\x40\x60\x01\x91\xe5\x15\x74\xbf\xd6\x03\x8d\x5a\x03\x42\x08\x3c\
+\x73\x73\x28\xe4\x0b\xd0\xe9\x75\xd0\xe9\x75\xc8\xe5\x04\x2c\x2f\
+\x2d\xe2\xe9\x93\xa7\xa8\xd5\x6a\x61\xb3\xd9\xa0\xd6\xf2\x5c\x4a\
+\x4a\x0c\x96\x8d\x8a\x81\x73\x23\x57\xcd\x66\xe3\x27\x47\x1c\x0e\
+\x15\xa5\x14\x5e\xaf\x17\xb1\x58\x0c\x4e\xa7\x13\x4a\xa5\x72\x97\
+\x37\xeb\xf1\xa0\x4e\xaf\x87\xd5\x6a\x2d\xcb\x94\x10\x09\x6b\x6b\
+\x6b\x08\x87\x17\x91\xcf\xe7\x21\x4a\x85\x08\x5b\x4a\x28\xe4\x31\
+\xba\xbe\xb1\x89\x6c\x36\x0b\x8f\xc7\x83\x64\x32\x85\x9e\x9e\x9e\
+\x32\x71\x00\x30\x9b\x4c\xd8\x58\x5f\xaf\x38\x2f\x96\xe5\x60\xb1\
+\x58\x71\xe2\xc4\x09\x98\x4d\x26\x02\x70\x5b\x65\x06\xae\xf1\x6b\
+\x31\x30\xf4\xa7\xa9\xa9\x67\x92\x24\x49\x70\x3a\x9d\x90\xcb\xe5\
+\x15\x42\x06\x83\x01\xf1\xed\x44\xd9\xe1\x96\x22\x93\x49\x23\xb2\
+\xb2\x92\xcb\x13\xf2\x2e\xbb\x77\x53\x10\xe9\xd5\x5c\x36\x17\x10\
+\xf3\x85\xb4\x20\xe4\xaa\x0a\x70\x1c\x07\x9d\x5e\x87\xad\xcd\xcd\
+\x8a\x3d\x4a\x28\xdc\xee\xd9\x1d\x42\xf1\x99\xeb\x97\x6b\xf3\x15\
+\x06\x8f\xee\x5c\x5f\x37\x09\x91\xc3\xdb\xe9\xe4\xd5\x87\x0f\x5d\
+\x3b\xc1\x60\x40\xa4\xa4\xb2\xdf\xcd\x26\x33\xd6\x37\x36\x2a\xd6\
+\x03\xc1\x80\x98\xcb\x09\xee\x89\xdb\xa3\x37\x80\x92\x71\x5d\x8a\
+\xf1\xf1\x71\xe9\xc1\xad\xd1\x6f\x28\xc4\x8e\x60\x20\xf4\x68\xd2\
+\xe5\x4a\x27\x92\xc9\x32\x8e\xd1\x68\x40\x34\x1a\xdd\x1d\x80\x00\
+\x90\x4a\x26\x11\x0a\x85\x04\x92\xa7\x67\xe9\x8b\xee\x61\xfe\xeb\
+\xc9\x2c\x45\xff\xe0\xa5\x73\x8c\x8c\xb9\xd1\x60\xb5\x2a\x5a\xec\
+\xad\x35\x9c\xec\xf9\x38\x9f\x7a\xf6\x0c\x0d\x8d\x36\x98\x4c\x46\
+\x10\x42\xe1\x9a\x9c\xdc\xc9\xe6\x73\x17\x1e\xdc\x1a\xfd\xb9\x18\
+\x5b\x35\x83\xbd\x78\x70\xe7\xfa\xed\x1c\x53\x78\x25\xb2\xb2\xf2\
+\xc7\xc4\xc4\xc4\x4e\xb1\xf6\x46\x93\x09\xeb\x2f\xba\x69\xde\xef\
+\x2f\x14\x0a\xf9\x87\xa5\xe2\x2f\x6d\x00\x00\x8f\xc7\x7e\x88\xde\
+\x1b\xbb\x76\x36\x5f\x10\xde\x76\xcf\xce\xae\x4d\xcf\x4c\xef\xe8\
+\xf6\xef\x47\x74\x6b\x13\xf1\xf8\x36\x96\x96\x97\x72\x3b\x05\x69\
+\x68\x6f\xdc\x4b\x95\x68\x2f\x7a\xcf\x8c\xa8\x14\x4a\x7c\x05\x06\
+\xe7\x95\x4a\x85\x4a\x14\x45\x41\x92\xc4\xe1\x7b\xb7\xae\xff\xf6\
+\xbf\x18\x14\xd1\x37\x74\xf9\x98\x5c\xc6\xdc\x61\xc1\x4c\xff\x39\
+\xf6\x5d\xc5\xdf\x03\xc0\x3f\x4b\x1d\x48\xe6\x9d\x4c\x36\xb6\x00\
+\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
 \x00\x00\x07\x53\
 \x89\
 \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -7579,6 +7801,46 @@
 \x14\xaa\x9a\xa3\x61\x0c\xfc\x0e\x5c\x02\xae\x00\x37\xf9\x3f\xda\
 \x7f\xdb\xbb\xc9\xf9\x3e\x97\xfc\xce\x00\x00\x00\x00\x49\x45\x4e\
 \x44\xae\x42\x60\x82\
+\x00\x00\x02\x5f\
+\x89\
+\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
+\x00\x00\x18\x00\x00\x00\x18\x08\x06\x00\x00\x00\xe0\x77\x3d\xf8\
+\x00\x00\x00\x04\x73\x42\x49\x54\x08\x08\x08\x08\x7c\x08\x64\x88\
+\x00\x00\x00\x09\x70\x48\x59\x73\x00\x00\x0d\xd7\x00\x00\x0d\xd7\
+\x01\x42\x28\x9b\x78\x00\x00\x00\x19\x74\x45\x58\x74\x53\x6f\x66\
+\x74\x77\x61\x72\x65\x00\x77\x77\x77\x2e\x69\x6e\x6b\x73\x63\x61\
+\x70\x65\x2e\x6f\x72\x67\x9b\xee\x3c\x1a\x00\x00\x01\xdc\x49\x44\
+\x41\x54\x48\x89\xed\x95\x31\x6b\x53\x51\x18\x86\x9f\x73\xce\x35\
+\xbd\x1a\x92\x96\xa6\x12\x6f\x17\x35\x01\x69\x4a\x47\x29\x45\x24\
+\x6a\x8a\xfe\x03\x25\x38\xe8\x22\x4e\x52\x08\x41\xff\x84\x38\x89\
+\x4e\x59\xe2\x20\x82\xb3\x60\x14\xdb\x24\x5a\x91\x8c\x0e\x56\x1a\
+\xa8\x0e\xc6\x24\xd0\xd0\xe6\x56\xed\x25\xf4\x9e\xe3\x20\xc6\x62\
+\x09\xd8\x5b\x70\xca\x37\x9e\xef\x3d\xdf\xf3\xbe\xc3\x77\x8e\x38\
+\x7f\x2d\xf7\x5e\x1b\x93\xe4\x00\x25\x10\x9d\x11\x54\xaa\xf4\xe8\
+\xee\xf7\xbf\x7b\x96\xaf\xf5\x54\x3a\x7d\x4e\x29\x29\x03\x03\x5e\
+\x57\xab\xb1\xde\xf6\x8f\x08\xb0\x17\x00\x70\xc8\x52\x48\xa9\x02\
+\x03\x04\x06\x33\xa0\x17\xdc\xf6\x3f\xd6\x10\x30\x04\x0c\x01\xff\
+\x01\x60\x05\xb9\x34\x26\x3e\x90\x34\x05\x39\xca\x2a\x00\x99\x0c\
+\x47\x80\xe6\x72\xf1\x61\x5f\x63\xa0\x26\x24\xf9\x40\x80\xa4\x29\
+\xc8\xf1\x50\x1b\x3b\x72\x1a\xa9\x6c\xa4\xb2\x49\x5d\x7a\xc9\xca\
+\x8b\x8b\x68\xdf\x43\xfb\x1e\xde\x56\x7d\x76\xa7\xd7\xbd\x17\x08\
+\x30\xca\x2a\xe1\x58\x06\x65\x85\xc1\xfc\x79\xe6\x7e\xc3\x10\x02\
+\x15\x8a\xe2\x36\x17\x67\x03\x01\x00\x26\x8e\x5f\x21\x3a\x39\x4f\
+\xe7\xd3\x13\xa2\xf1\x34\x00\x93\x33\xb7\x71\xdb\x55\x62\x27\xb3\
+\xb8\x5f\x5f\xe1\x36\x17\xb1\xa4\x10\xeb\x4b\x4b\xe5\xf1\xfd\x0c\
+\xcf\xcc\x33\xb2\xf1\xe5\x19\xfe\xce\x37\x9c\x99\x3b\x18\xdd\x63\
+\xb3\xf1\x9c\x48\xfc\x2c\xe1\xa3\x73\xb4\x57\xee\xe3\xb6\x2a\x00\
+\x58\x42\x6d\x26\x60\xcc\xde\x67\x80\x0d\x30\xb8\xad\x32\xf1\xa9\
+\x5b\x6c\xb5\xdf\xd0\xfe\xf8\x00\x80\xe8\xb1\x0b\xb8\xad\x72\x5f\
+\x28\x8c\x19\xf4\x55\x0c\xae\xe5\xa2\x30\x20\x98\x48\x5c\x25\x71\
+\xa6\x80\xf6\xb7\xe9\x7c\x7e\x4a\xec\xc4\x65\xa4\x3a\xcc\xda\xdb\
+\x1b\xac\xaf\x3d\x06\x4c\xf0\x3d\x70\x52\x0b\x38\xd3\x39\xea\x95\
+\x2c\xdd\x46\x89\xf8\xa9\x9b\x74\x1b\x25\xea\x95\x2c\xce\x74\x0e\
+\x27\xb5\x70\xb0\x04\x52\xd9\x68\xdd\x03\xa3\x01\x98\xbb\x6e\x78\
+\x57\x14\xbf\x04\x42\x22\x65\x08\xed\x7b\xc1\x12\x18\xa8\x69\xdf\
+\xeb\x0f\xdf\x2b\xd0\x68\xdf\xc3\x40\x2d\x10\x40\x48\xf2\x06\x6a\
+\xbb\xcf\xfa\xee\x77\x99\x10\x92\xfc\x4f\xfd\xc2\xaa\x73\x0e\x12\
+\x9d\x40\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82\
 \x00\x00\x04\xfd\
 \x89\
 \x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52\x00\
@@ -8024,6 +8286,10 @@
 \x09\x28\xf5\xe7\
 \x00\x66\
 \x00\x74\x00\x6f\x00\x6f\x00\x6c\x00\x73\x00\x5f\x00\x6c\x00\x6f\x00\x67\x00\x6f\x00\x2e\x00\x70\x00\x6e\x00\x67\
+\x00\x0c\
+\x09\xd4\x06\xc7\
+\x00\x64\
+\x00\x65\x00\x6c\x00\x61\x00\x75\x00\x6e\x00\x61\x00\x79\x00\x2e\x00\x70\x00\x6e\x00\x67\
 \x00\x15\
 \x0a\xb1\xae\x07\
 \x00\x64\
@@ -8109,6 +8375,10 @@
 \x00\x65\
 \x00\x78\x00\x70\x00\x6f\x00\x72\x00\x74\x00\x5f\x00\x67\x00\x65\x00\x6f\x00\x6d\x00\x65\x00\x74\x00\x72\x00\x79\x00\x2e\x00\x70\
 \x00\x6e\x00\x67\
+\x00\x10\
+\x05\x40\x6b\xe7\
+\x00\x6c\
+\x00\x61\x00\x79\x00\x65\x00\x72\x00\x5f\x00\x65\x00\x78\x00\x74\x00\x65\x00\x6e\x00\x74\x00\x2e\x00\x70\x00\x6e\x00\x67\
 \x00\x13\
 \x06\xd5\x17\xc7\
 \x00\x73\
@@ -8133,91 +8403,95 @@
 qt_resource_struct = "\
 \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
 \x00\x00\x00\x00\x00\x02\x00\x00\x00\x02\x00\x00\x00\x02\
-\x00\x00\x00\x24\x00\x02\x00\x00\x00\x2a\x00\x00\x00\x2e\
-\x00\x00\x00\x10\x00\x02\x00\x00\x00\x2a\x00\x00\x00\x04\
-\x00\x00\x03\x6c\x00\x00\x00\x00\x00\x01\x00\x01\x6e\x70\
-\x00\x00\x02\xd2\x00\x00\x00\x00\x00\x01\x00\x01\x4e\xaa\
-\x00\x00\x03\xe2\x00\x00\x00\x00\x00\x01\x00\x01\x86\x54\
-\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x01\x00\x00\xd0\x92\
-\x00\x00\x03\x84\x00\x00\x00\x00\x00\x01\x00\x01\x74\xc5\
-\x00\x00\x00\xe6\x00\x00\x00\x00\x00\x01\x00\x00\xdb\x54\
-\x00\x00\x00\x6a\x00\x00\x00\x00\x00\x01\x00\x00\xc1\x2f\
-\x00\x00\x05\x32\x00\x00\x00\x00\x00\x01\x00\x01\xc9\x5a\
-\x00\x00\x02\x1c\x00\x00\x00\x00\x00\x01\x00\x01\x19\xef\
-\x00\x00\x04\x8a\x00\x00\x00\x00\x00\x01\x00\x01\xa9\x20\
-\x00\x00\x01\xcc\x00\x00\x00\x00\x00\x01\x00\x01\x09\x30\
-\x00\x00\x04\xf4\x00\x00\x00\x00\x00\x01\x00\x01\xbc\xe0\
-\x00\x00\x05\x5e\x00\x00\x00\x00\x00\x01\x00\x01\xcd\xf4\
-\x00\x00\x04\xb4\x00\x00\x00\x00\x00\x01\x00\x01\xaf\xb7\
-\x00\x00\x02\xf0\x00\x00\x00\x00\x00\x01\x00\x01\x55\xc4\
-\x00\x00\x03\x1c\x00\x00\x00\x00\x00\x01\x00\x01\x5b\x84\
-\x00\x00\x00\x8e\x00\x00\x00\x00\x00\x01\x00\x00\xc8\x9b\
-\x00\x00\x00\xcc\x00\x00\x00\x00\x00\x01\x00\x00\xd5\x72\
-\x00\x00\x05\xb6\x00\x00\x00\x00\x00\x01\x00\x01\xd8\x12\
-\x00\x00\x02\x64\x00\x00\x00\x00\x00\x01\x00\x01\x26\xcd\
-\x00\x00\x02\x7e\x00\x00\x00\x00\x00\x01\x00\x01\x31\x5b\
-\x00\x00\x05\xe4\x00\x00\x00\x00\x00\x01\x00\x01\xdb\xbd\
-\x00\x00\x01\xa2\x00\x00\x00\x00\x00\x01\x00\x01\x04\x55\
-\x00\x00\x04\x60\x00\x00\x00\x00\x00\x01\x00\x01\xa1\xda\
-\x00\x00\x02\xa2\x00\x00\x00\x00\x00\x01\x00\x01\x47\x53\
-\x00\x00\x01\x4a\x00\x00\x00\x00\x00\x01\x00\x00\xf3\xf7\
-\x00\x00\x01\x82\x00\x00\x00\x00\x00\x01\x00\x00\xfe\x7e\
-\x00\x00\x01\x6c\x00\x00\x00\x00\x00\x01\x00\x00\xfa\xa4\
-\x00\x00\x05\x8a\x00\x00\x00\x00\x00\x01\x00\x01\xd2\xf5\
-\x00\x00\x04\x20\x00\x00\x00\x00\x00\x01\x00\x01\x95\x53\
-\x00\x00\x00\x54\x00\x00\x00\x00\x00\x01\x00\x00\xb8\x76\
-\x00\x00\x05\x12\x00\x00\x00\x00\x00\x01\x00\x01\xc4\xc6\
-\x00\x00\x01\x04\x00\x00\x00\x00\x00\x01\x00\x00\xe2\x5f\
-\x00\x00\x04\xd2\x00\x00\x00\x00\x00\x01\x00\x01\xb7\x0b\
-\x00\x00\x00\x30\x00\x00\x00\x00\x00\x01\x00\x00\xb1\x9f\
-\x00\x00\x04\x3e\x00\x00\x00\x00\x00\x01\x00\x01\x9a\x4e\
-\x00\x00\x04\x02\x00\x00\x00\x00\x00\x01\x00\x01\x8e\xeb\
-\x00\x00\x01\xf4\x00\x00\x00\x00\x00\x01\x00\x01\x0f\x84\
-\x00\x00\x03\xb4\x00\x00\x00\x00\x00\x01\x00\x01\x7c\x32\
-\x00\x00\x01\x1e\x00\x00\x00\x00\x00\x01\x00\x00\xec\x50\
-\x00\x00\x03\x44\x00\x00\x00\x00\x00\x01\x00\x01\x65\x33\
-\x00\x00\x02\x44\x00\x00\x00\x00\x00\x01\x00\x01\x20\xeb\
-\x00\x00\x03\x6c\x00\x00\x00\x00\x00\x01\x00\x00\x6d\x8f\
-\x00\x00\x02\xd2\x00\x00\x00\x00\x00\x01\x00\x00\x5d\xf4\
-\x00\x00\x03\xe2\x00\x00\x00\x00\x00\x01\x00\x00\x78\x85\
+\x00\x00\x00\x24\x00\x02\x00\x00\x00\x2c\x00\x00\x00\x30\
+\x00\x00\x00\x10\x00\x02\x00\x00\x00\x2c\x00\x00\x00\x04\
+\x00\x00\x03\x8a\x00\x00\x00\x00\x00\x01\x00\x01\x7b\xf3\
+\x00\x00\x02\xf0\x00\x00\x00\x00\x00\x01\x00\x01\x5c\x2d\
+\x00\x00\x04\x00\x00\x00\x00\x00\x00\x01\x00\x01\x93\xd7\
+\x00\x00\x00\xb6\x00\x00\x00\x00\x00\x01\x00\x00\xd8\x85\
+\x00\x00\x03\xa2\x00\x00\x00\x00\x00\x01\x00\x01\x82\x48\
+\x00\x00\x00\xe6\x00\x00\x00\x00\x00\x01\x00\x00\xe3\x47\
+\x00\x00\x00\x6a\x00\x00\x00\x00\x00\x01\x00\x00\xc9\x22\
+\x00\x00\x05\x50\x00\x00\x00\x00\x00\x01\x00\x01\xd6\xdd\
+\x00\x00\x02\x1c\x00\x00\x00\x00\x00\x01\x00\x01\x21\xe2\
+\x00\x00\x05\x7c\x00\x00\x00\x00\x00\x01\x00\x01\xdb\x77\
+\x00\x00\x04\xa8\x00\x00\x00\x00\x00\x01\x00\x01\xb6\xa3\
+\x00\x00\x01\xcc\x00\x00\x00\x00\x00\x01\x00\x01\x11\x23\
+\x00\x00\x05\x12\x00\x00\x00\x00\x00\x01\x00\x01\xca\x63\
+\x00\x00\x05\xa2\x00\x00\x00\x00\x00\x01\x00\x01\xdd\xda\
+\x00\x00\x04\xd2\x00\x00\x00\x00\x00\x01\x00\x01\xbd\x3a\
+\x00\x00\x03\x0e\x00\x00\x00\x00\x00\x01\x00\x01\x63\x47\
+\x00\x00\x03\x3a\x00\x00\x00\x00\x00\x01\x00\x01\x69\x07\
+\x00\x00\x00\x8e\x00\x00\x00\x00\x00\x01\x00\x00\xd0\x8e\
+\x00\x00\x00\xcc\x00\x00\x00\x00\x00\x01\x00\x00\xdd\x65\
+\x00\x00\x05\xfa\x00\x00\x00\x00\x00\x01\x00\x01\xe7\xf8\
+\x00\x00\x02\x64\x00\x00\x00\x00\x00\x01\x00\x01\x2e\xc0\
+\x00\x00\x02\x7e\x00\x00\x00\x00\x00\x01\x00\x01\x39\x4e\
+\x00\x00\x06\x28\x00\x00\x00\x00\x00\x01\x00\x01\xeb\xa3\
+\x00\x00\x02\xa2\x00\x00\x00\x00\x00\x01\x00\x01\x4f\x46\
+\x00\x00\x01\xa2\x00\x00\x00\x00\x00\x01\x00\x01\x0c\x48\
+\x00\x00\x04\x7e\x00\x00\x00\x00\x00\x01\x00\x01\xaf\x5d\
+\x00\x00\x02\xc0\x00\x00\x00\x00\x00\x01\x00\x01\x54\xd6\
+\x00\x00\x01\x4a\x00\x00\x00\x00\x00\x01\x00\x00\xfb\xea\
+\x00\x00\x01\x82\x00\x00\x00\x00\x00\x01\x00\x01\x06\x71\
+\x00\x00\x01\x6c\x00\x00\x00\x00\x00\x01\x00\x01\x02\x97\
+\x00\x00\x05\xce\x00\x00\x00\x00\x00\x01\x00\x01\xe2\xdb\
+\x00\x00\x04\x3e\x00\x00\x00\x00\x00\x01\x00\x01\xa2\xd6\
+\x00\x00\x00\x54\x00\x00\x00\x00\x00\x01\x00\x00\xc0\x69\
+\x00\x00\x05\x30\x00\x00\x00\x00\x00\x01\x00\x01\xd2\x49\
+\x00\x00\x01\x04\x00\x00\x00\x00\x00\x01\x00\x00\xea\x52\
+\x00\x00\x04\xf0\x00\x00\x00\x00\x00\x01\x00\x01\xc4\x8e\
+\x00\x00\x00\x30\x00\x00\x00\x00\x00\x01\x00\x00\xb9\x92\
+\x00\x00\x04\x5c\x00\x00\x00\x00\x00\x01\x00\x01\xa7\xd1\
+\x00\x00\x04\x20\x00\x00\x00\x00\x00\x01\x00\x01\x9c\x6e\
+\x00\x00\x01\xf4\x00\x00\x00\x00\x00\x01\x00\x01\x17\x77\
+\x00\x00\x03\xd2\x00\x00\x00\x00\x00\x01\x00\x01\x89\xb5\
+\x00\x00\x01\x1e\x00\x00\x00\x00\x00\x01\x00\x00\xf4\x43\
+\x00\x00\x03\x62\x00\x00\x00\x00\x00\x01\x00\x01\x72\xb6\
+\x00\x00\x02\x44\x00\x00\x00\x00\x00\x01\x00\x01\x28\xde\
+\x00\x00\x03\x8a\x00\x00\x00\x00\x00\x01\x00\x00\x73\x1f\
+\x00\x00\x02\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x63\x84\
+\x00\x00\x04\x00\x00\x00\x00\x00\x00\x01\x00\x00\x7e\x15\
 \x00\x00\x00\xb6\x00\x00\x00\x00\x00\x01\x00\x00\x13\x9c\
-\x00\x00\x03\x84\x00\x00\x00\x00\x00\x01\x00\x00\x70\xcd\
+\x00\x00\x03\xa2\x00\x00\x00\x00\x00\x01\x00\x00\x76\x5d\
 \x00\x00\x00\xe6\x00\x00\x00\x00\x00\x01\x00\x00\x19\x04\
 \x00\x00\x00\x6a\x00\x00\x00\x00\x00\x01\x00\x00\x09\xbd\
-\x00\x00\x05\x32\x00\x00\x00\x00\x00\x01\x00\x00\xa0\x0a\
+\x00\x00\x05\x50\x00\x00\x00\x00\x00\x01\x00\x00\xa5\x9a\
 \x00\x00\x02\x1c\x00\x00\x00\x00\x00\x01\x00\x00\x3a\xc5\
-\x00\x00\x04\x8a\x00\x00\x00\x00\x00\x01\x00\x00\x8a\x39\
+\x00\x00\x05\x7c\x00\x00\x00\x00\x00\x01\x00\x00\xa8\x7b\
+\x00\x00\x04\xa8\x00\x00\x00\x00\x00\x01\x00\x00\x8f\xc9\
 \x00\x00\x01\xcc\x00\x00\x00\x00\x00\x01\x00\x00\x33\xf7\
-\x00\x00\x04\xf4\x00\x00\x00\x00\x00\x01\x00\x00\x96\x18\
-\x00\x00\x05\x5e\x00\x00\x00\x00\x00\x01\x00\x00\xa2\xeb\
-\x00\x00\x04\xb4\x00\x00\x00\x00\x00\x01\x00\x00\x8d\x88\
-\x00\x00\x02\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x61\x96\
-\x00\x00\x03\x1c\x00\x00\x00\x00\x00\x01\x00\x00\x64\x12\
+\x00\x00\x05\x12\x00\x00\x00\x00\x00\x01\x00\x00\x9b\xa8\
+\x00\x00\x05\xa2\x00\x00\x00\x00\x00\x01\x00\x00\xaa\xde\
+\x00\x00\x04\xd2\x00\x00\x00\x00\x00\x01\x00\x00\x93\x18\
+\x00\x00\x03\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x67\x26\
+\x00\x00\x03\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x69\xa2\
 \x00\x00\x00\x8e\x00\x00\x00\x00\x00\x01\x00\x00\x0d\x65\
 \x00\x00\x00\xcc\x00\x00\x00\x00\x00\x01\x00\x00\x17\x33\
-\x00\x00\x05\xb6\x00\x00\x00\x00\x00\x01\x00\x00\xab\xd0\
+\x00\x00\x05\xfa\x00\x00\x00\x00\x00\x01\x00\x00\xb3\xc3\
 \x00\x00\x02\x64\x00\x00\x00\x00\x00\x01\x00\x00\x41\x8a\
 \x00\x00\x02\x7e\x00\x00\x00\x00\x00\x01\x00\x00\x42\x98\
-\x00\x00\x05\xe4\x00\x00\x00\x00\x00\x01\x00\x00\xad\xfd\
+\x00\x00\x06\x28\x00\x00\x00\x00\x00\x01\x00\x00\xb5\xf0\
+\x00\x00\x02\xa2\x00\x00\x00\x00\x00\x01\x00\x00\x58\x90\
 \x00\x00\x01\xa2\x00\x00\x00\x00\x00\x01\x00\x00\x31\x1f\
-\x00\x00\x04\x60\x00\x00\x00\x00\x00\x01\x00\x00\x88\xd6\
-\x00\x00\x02\xa2\x00\x00\x00\x00\x00\x01\x00\x00\x58\x90\
+\x00\x00\x04\x7e\x00\x00\x00\x00\x00\x01\x00\x00\x8e\x66\
+\x00\x00\x02\xc0\x00\x00\x00\x00\x00\x01\x00\x00\x5e\x20\
 \x00\x00\x01\x4a\x00\x00\x00\x00\x00\x01\x00\x00\x25\x4f\
 \x00\x00\x01\x82\x00\x00\x00\x00\x00\x01\x00\x00\x2d\xad\
 \x00\x00\x01\x6c\x00\x00\x00\x00\x00\x01\x00\x00\x28\x55\
-\x00\x00\x05\x8a\x00\x00\x00\x00\x00\x01\x00\x00\xa7\x57\
-\x00\x00\x04\x20\x00\x00\x00\x00\x00\x01\x00\x00\x80\x2b\
+\x00\x00\x05\xce\x00\x00\x00\x00\x00\x01\x00\x00\xaf\x4a\
+\x00\x00\x04\x3e\x00\x00\x00\x00\x00\x01\x00\x00\x85\xbb\
 \x00\x00\x00\x54\x00\x00\x00\x00\x00\x01\x00\x00\x01\x04\
-\x00\x00\x05\x12\x00\x00\x00\x00\x00\x01\x00\x00\x9b\x3f\
+\x00\x00\x05\x30\x00\x00\x00\x00\x00\x01\x00\x00\xa0\xcf\
 \x00\x00\x01\x04\x00\x00\x00\x00\x00\x01\x00\x00\x1d\xe8\
-\x00\x00\x04\xd2\x00\x00\x00\x00\x00\x01\x00\x00\x92\x34\
+\x00\x00\x04\xf0\x00\x00\x00\x00\x00\x01\x00\x00\x97\xc4\
 \x00\x00\x00\x30\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
-\x00\x00\x04\x3e\x00\x00\x00\x00\x00\x01\x00\x00\x83\x8d\
-\x00\x00\x04\x02\x00\x00\x00\x00\x00\x01\x00\x00\x7d\x6e\
+\x00\x00\x04\x5c\x00\x00\x00\x00\x00\x01\x00\x00\x89\x1d\
+\x00\x00\x04\x20\x00\x00\x00\x00\x00\x01\x00\x00\x82\xfe\
 \x00\x00\x01\xf4\x00\x00\x00\x00\x00\x01\x00\x00\x37\x71\
-\x00\x00\x03\xb4\x00\x00\x00\x00\x00\x01\x00\x00\x76\x38\
+\x00\x00\x03\xd2\x00\x00\x00\x00\x00\x01\x00\x00\x7b\xc8\
 \x00\x00\x01\x1e\x00\x00\x00\x00\x00\x01\x00\x00\x22\x2e\
-\x00\x00\x03\x44\x00\x00\x00\x00\x00\x01\x00\x00\x67\x31\
+\x00\x00\x03\x62\x00\x00\x00\x00\x00\x01\x00\x00\x6c\xc1\
 \x00\x00\x02\x44\x00\x00\x00\x00\x00\x01\x00\x00\x3d\xd6\
 "
 

Modified: trunk/qgis/python/plugins/fTools/resources.qrc
===================================================================
--- trunk/qgis/python/plugins/fTools/resources.qrc	2009-03-05 15:06:30 UTC (rev 10264)
+++ trunk/qgis/python/plugins/fTools/resources.qrc	2009-03-09 00:20:39 UTC (rev 10265)
@@ -42,6 +42,8 @@
         <file>icons/default/vector_grid.png</file>
         <file>icons/default/split_layer.png</file>
 		<file>icons/default/neighbour.png</file>
+		<file>icons/default/delaunay.png</file>
+		<file>icons/default/layer_extent.png</file>
 		<file>icons/gis/single_to_multi.png</file>
 		<file>icons/gis/simplify.png</file>
 		<file>icons/gis/difference.png</file>
@@ -84,5 +86,7 @@
         <file>icons/gis/vector_grid.png</file>
         <file>icons/gis/split_layer.png</file>
 		<file>icons/gis/neighbour.png</file>
+		<file>icons/gis/delaunay.png</file>
+		<file>icons/gis/layer_extent.png</file>
     </qresource>
 </RCC>

Modified: trunk/qgis/python/plugins/fTools/tools/CMakeLists.txt
===================================================================
--- trunk/qgis/python/plugins/fTools/tools/CMakeLists.txt	2009-03-05 15:06:30 UTC (rev 10264)
+++ trunk/qgis/python/plugins/fTools/tools/CMakeLists.txt	2009-03-09 00:20:39 UTC (rev 10265)
@@ -53,6 +53,7 @@
 doVectorGrid.py
 frmRandPoints.py
 ftools_utils.py
+voronoi.py
 doVectorSplit.py
 frmRandPoints.ui
 )

Modified: trunk/qgis/python/plugins/fTools/tools/doGeometry.py
===================================================================
--- trunk/qgis/python/plugins/fTools/tools/doGeometry.py	2009-03-05 15:06:30 UTC (rev 10264)
+++ trunk/qgis/python/plugins/fTools/tools/doGeometry.py	2009-03-09 00:20:39 UTC (rev 10265)
@@ -4,6 +4,7 @@
 from frmGeometry import Ui_Dialog
 import ftools_utils
 import math
+from itertools import izip
 
 class GeometryDialog(QDialog, Ui_Dialog):
 
@@ -92,7 +93,7 @@
 			self.label_2.setText( self.tr( "Output shapefile" ) )
 			self.cmbField.setVisible(False)
 			self.field_label.setVisible(False)
-		else: # Polygon centroids
+		elif self.myFunction == 7: # Polygon centroids
 			self.setWindowTitle( self.tr( "Polygon centroids" ) )
 			self.label_2.setText( self.tr( "Output point shapefile" ) )
 			self.label_3.setText( self.tr( "Input polygon vector layer" ) )
@@ -100,6 +101,18 @@
 			self.lineEdit.setVisible( False )
 			self.cmbField.setVisible( False )
 			self.field_label.setVisible( False )
+		else:
+			if self.myFunction == 8: # Delaunay triangulation
+				self.setWindowTitle( self.tr( "Delaunay triangulation" ) )
+				self.label_3.setText( self.tr( "Input point vector layer" ) )
+			else: # Polygon from layer extent
+				self.setWindowTitle( self.tr( "Polygon from layer extent" ) )
+				self.label_3.setText( self.tr( "Input layer" ) )
+			self.label_2.setText( self.tr( "Output polygon shapefile" ) )
+			self.label.setVisible( False )
+			self.lineEdit.setVisible( False )
+			self.cmbField.setVisible( False )
+			self.field_label.setVisible( False )
 		self.resize( 381, 100 )
 		myList = []
 		self.inShape.clear()
@@ -107,6 +120,10 @@
 			myList = ftools_utils.getLayerNames( [ QGis.Polygon, QGis.Line ] )    
 		elif self.myFunction == 4 or self.myFunction == 7:
 			myList = ftools_utils.getLayerNames( [ QGis.Polygon ] )
+		elif self.myFunction == 8:
+			myList = ftools_utils.getLayerNames( [ QGis.Point ] )
+		elif self.myFunction == 9:
+			myList = ftools_utils.getLayerNames( "all" )
 		else:
 			myList = ftools_utils.getLayerNames( [ QGis.Point, QGis.Line, QGis.Polygon ] )    
 		self.inShape.addItems( myList )
@@ -119,9 +136,14 @@
 #5:	Export/Add geometry columns
 #6:	Simplify geometries
 #7:	Polygon centroids
+#8: Delaunay triangulation
+#9: Polygon from layer extent
 
 	def geometry( self, myLayer, myParam, myField ):
-		vlayer = ftools_utils.getVectorLayerByName( myLayer )
+		if self.myFunction == 9:
+			vlayer = ftools_utils.getMapLayerByName( myLayer )
+		else:
+			vlayer = ftools_utils.getVectorLayerByName( myLayer )
 		error = False
 		check = QFile( self.shapefileName )
 		if check.exists():
@@ -143,21 +165,21 @@
 	def runFinishedFromThread( self, success ):
 		self.testThread.stop()
 		if success == "math_error":
-			QMessageBox.warning( self, "Geoprocessing", self.tr( "Error processing specified tolerance!" ) + "\n"
+			QMessageBox.warning( self, "Geometry", self.tr( "Error processing specified tolerance!" ) + "\n"
 			+ self.tr( "Please choose larger tolerance..." ) )
 			if not QgsVectorFileWriter.deleteShapeFile( self.shapefileName ):
-				QMessageBox.warning( self, "Geoprocessing", self.tr( "Unable to delete incomplete shapefile." ) )
+				QMessageBox.warning( self, "Geometry", self.tr( "Unable to delete incomplete shapefile." ) )
 		else: 
 			self.cancel_close.setText( "Close" )
 			QObject.disconnect( self.cancel_close, SIGNAL( "clicked()" ), self.cancelThread )
 			if success:
-				addToTOC = QMessageBox.question( self, "Geoprocessing", self.tr( "Created output shapefile:" ) + "\n" + 
+				addToTOC = QMessageBox.question( self, "Geometry", self.tr( "Created output shapefile:" ) + "\n" + 
 				unicode( self.shapefileName ) + "\n\n" + self.tr( "Would you like to add the new layer to the TOC?" ), 
 				QMessageBox.Yes, QMessageBox.No, QMessageBox.NoButton )
 				if addToTOC == QMessageBox.Yes:
 					ftools_utils.addShapeToCanvas( unicode( self.shapefileName ) )
 			else:
-				QMessageBox.warning( self, "Geoprocessing", self.tr( "Error writing output shapefile." ) )
+				QMessageBox.warning( self, "Geometry", self.tr( "Error writing output shapefile." ) )
 				
 	def runStatusFromThread( self, status ):
 		self.progressBar.setValue( status )
@@ -193,6 +215,10 @@
 			success = self.simplify_geometry()
 		elif self.myFunction == 7: # Polygon centroids
 			success = self.polygon_centroids()
+		elif self.myFunction == 8: # Delaunay triangulation
+			success = self.delaunay_triangulation()
+		elif self.myFunction == 9: # Polygon from layer extent
+			success = self.layer_extent()
 		self.emit( SIGNAL( "runFinished(PyQt_PyObject)" ), success )
 		self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
 
@@ -452,7 +478,109 @@
 			self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ),  nElement )
 		del writer
 		return True
+		
+	def delaunay_triangulation( self ):
+		import voronoi
+		vprovider = self.vlayer.dataProvider()
+		allAttrs = vprovider.attributeIndexes()
+		vprovider.select( allAttrs )
+		fields = {
+		0 : QgsField( "POINTA", QVariant.Double ),
+		1 : QgsField( "POINTB", QVariant.Double ),
+		2 : QgsField( "POINTC", QVariant.Double ) }
+		writer = QgsVectorFileWriter( self.myName, self.myEncoding,
+		fields, QGis.WKBPolygon, vprovider.crs() )
+		inFeat = QgsFeature()
+		points = []
+		print "here"
+		while vprovider.nextFeature( inFeat ):
+			inGeom = QgsGeometry( inFeat.geometry() )
+			point = inGeom.asPoint()
+			points.append( point )
+		print "or here"
+		vprovider.rewind()
+		vprovider.select( allAttrs )
+		triangles = voronoi.computeDelaunayTriangulation( points )
+		feat = QgsFeature()
+		nFeat = len( triangles )
+		nElement = 0
+		self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
+		self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, nFeat ) )
+		for triangle in triangles:
+			indicies = list( triangle )
+			indicies.append( indicies[ 0 ] )
+			polygon = []
+			step = 0
+			for index in indicies:
+				vprovider.featureAtId( index, feat, True,  allAttrs )
+				geom = QgsGeometry( feat.geometry() )
+				point = QgsPoint( geom.asPoint() )
+				polygon.append( point )
+				feat.addAttribute( step, QVariant( index ) )
+				step += 1
+			geometry = QgsGeometry().fromPolygon( [ polygon ] )
+			feat.setGeometry( geometry )			
+			writer.addFeature( feat )
+			nElement += 1
+			self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ),  nElement )
+		del writer
+		return True
+		
+	def layer_extent( self ):
+		self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ), 0 )
+		self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, 0 ) )
+		fields = {
+		0 : QgsField( "MINX", QVariant.Double ),
+		1 : QgsField( "MINY", QVariant.Double ),
+		2 : QgsField( "MAXX", QVariant.Double ),
+		3 : QgsField( "MAXY", QVariant.Double ),
+		4 : QgsField( "CNTX", QVariant.Double ),
+		5 : QgsField( "CNTY", QVariant.Double ),
+		6 : QgsField( "AREA", QVariant.Double ),
+		7 : QgsField( "PERIM", QVariant.Double ),
+		8 : QgsField( "HEIGHT", QVariant.Double ),
+		9 : QgsField( "WIDTH", QVariant.Double ) }
 
+		writer = QgsVectorFileWriter( self.myName, self.myEncoding, 
+		fields, QGis.WKBPolygon, self.vlayer.srs() )
+		rect = self.vlayer.extent()
+		minx = rect.xMinimum()
+		miny = rect.yMinimum()
+		maxx = rect.xMaximum()
+		maxy = rect.yMaximum()
+		height = rect.height()
+		width = rect.width()
+		cntx = minx + ( width / 2.0 )
+		cnty = miny + ( height / 2.0 )
+		area = width * height
+		perim = ( 2 * width ) + (2 * height )
+		rect = [
+		QgsPoint( minx, miny ),
+		QgsPoint( minx, maxy ),
+		QgsPoint( maxx, maxy ),
+		QgsPoint( maxx, miny ),
+		QgsPoint( minx, miny ) ]
+		geometry = QgsGeometry().fromPolygon( [ rect ] )
+		feat = QgsFeature()
+		feat.setGeometry( geometry )
+		feat.setAttributeMap( {
+		0 : QVariant( minx ),
+		1 : QVariant( miny ),
+		2 : QVariant( maxx ),
+		3 : QVariant( maxy ),
+		4 : QVariant( cntx ),
+		5 : QVariant( cnty ),
+		6 : QVariant( area ),
+		7 : QVariant( perim ),
+		8 : QVariant( height ),
+		9 : QVariant( width ) } )
+		writer.addFeature( feat )
+		self.emit( SIGNAL( "runRange(PyQt_PyObject)" ), ( 0, 100 ) )
+		self.emit( SIGNAL( "runStatus(PyQt_PyObject)" ),  0 )
+		del writer
+
+		return True
+
 	def extractAsSimple( self, geom, tolerance ):
 		temp_geom1 = []
 		temp_geom2 = []

Modified: trunk/qgis/python/plugins/fTools/tools/doRandPoints.py
===================================================================
--- trunk/qgis/python/plugins/fTools/tools/doRandPoints.py	2009-03-05 15:06:30 UTC (rev 10264)
+++ trunk/qgis/python/plugins/fTools/tools/doRandPoints.py	2009-03-09 00:20:39 UTC (rev 10265)
@@ -218,7 +218,6 @@
 			if not QgsVectorFileWriter.deleteShapeFile(self.shapefileName):
 				return
 		writer = QgsVectorFileWriter(self.shapefileName, self.encoding, fields, QGis.WKBPoint, None)
-		#writer = QgsVectorFileWriter(unicode(outPath), "CP1250", fields, QGis.WKBPoint, None)
 		idVar = 0
 		count = 70.00
 		add = 30.00 / len(points)

Modified: trunk/qgis/python/plugins/fTools/tools/ftools_utils.py
===================================================================
--- trunk/qgis/python/plugins/fTools/tools/ftools_utils.py	2009-03-05 15:06:30 UTC (rev 10264)
+++ trunk/qgis/python/plugins/fTools/tools/ftools_utils.py	2009-03-09 00:20:39 UTC (rev 10265)
@@ -159,10 +159,14 @@
 def getLayerNames( vTypes ):
 	layermap = QgsMapLayerRegistry.instance().mapLayers()
 	layerlist = []
-	for name, layer in layermap.iteritems():
-		if layer.type() == QgsMapLayer.VectorLayer:
-			if layer.geometryType() in vTypes and not layer.name() in layerlist:
-				layerlist.append( unicode( layer.name() ) )
+	if vTypes == "all":
+		for name, layer in layermap.iteritems():
+			layerlist.append( unicode( layer.name() ) )
+	else:
+		for name, layer in layermap.iteritems():
+			if layer.type() == QgsMapLayer.VectorLayer:
+				if layer.geometryType() in vTypes:
+					layerlist.append( unicode( layer.name() ) )
 	return layerlist
 
 # Return list of names of all fields from input QgsVectorLayer

Added: trunk/qgis/python/plugins/fTools/tools/voronoi.py
===================================================================
--- trunk/qgis/python/plugins/fTools/tools/voronoi.py	                        (rev 0)
+++ trunk/qgis/python/plugins/fTools/tools/voronoi.py	2009-03-09 00:20:39 UTC (rev 10265)
@@ -0,0 +1,838 @@
+#############################################################################
+#
+# Voronoi diagram calculator/ Delaunay triangulator
+# Translated to Python by Bill Simons
+# September, 2005
+#
+# Calculate Delaunay triangulation or the Voronoi polygons for a set of 
+# 2D input points.
+#
+# Derived from code bearing the following notice:
+#
+#  The author of this software is Steven Fortune.  Copyright (c) 1994 by AT&T
+#  Bell Laboratories.
+#  Permission to use, copy, modify, and distribute this software for any
+#  purpose without fee is hereby granted, provided that this entire notice
+#  is included in all copies of any software which is or includes a copy
+#  or modification of this software and in all copies of the supporting
+#  documentation for such software.
+#  THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+#  WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
+#  REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+#  OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+#
+# Comments were incorporated from Shane O'Sullivan's translation of the 
+# original code into C++ (http://mapviewer.skynet.ie/voronoi.html)
+#
+# Steve Fortune's homepage: http://netlib.bell-labs.com/cm/cs/who/sjf/index.html
+#
+#############################################################################
+
+def usage():
+    print """
+voronoi - compute Voronoi diagram or Delaunay triangulation
+
+voronoi [-t -p -d]  [filename]
+
+Voronoi reads from filename (or standard input if no filename given) for a set 
+of points in the plane and writes either the Voronoi diagram or the Delaunay 
+triangulation to the standard output.  Each input line should consist of two 
+real numbers, separated by white space.
+
+If option -t is present, the Delaunay triangulation is produced. 
+Each output line is a triple i j k, which are the indices of the three points
+in a Delaunay triangle. Points are numbered starting at 0.
+
+If option -t is not present, the Voronoi diagram is produced.  
+There are four output record types.
+
+s a b      indicates that an input point at coordinates a b was seen.
+l a b c    indicates a line with equation ax + by = c.
+v a b      indicates a vertex at a b.
+e l v1 v2  indicates a Voronoi segment which is a subsegment of line number l
+           with endpoints numbered v1 and v2.  If v1 or v2 is -1, the line 
+           extends to infinity.
+
+Other options include:
+
+d    Print debugging info
+
+p    Produce output suitable for input to plot (1), rather than the forms 
+     described above.
+
+On unsorted data uniformly distributed in the unit square, voronoi uses about 
+20n+140 bytes of storage.
+
+AUTHOR
+Steve J. Fortune (1987) A Sweepline Algorithm for Voronoi Diagrams,
+Algorithmica 2, 153-174.
+"""
+
+#############################################################################
+#
+# For programmatic use two functions are available:
+#
+#   computeVoronoiDiagram(points)
+#
+#        Takes a list of point objects (which must have x and y fields).
+#        Returns a 3-tuple of:
+#
+#           (1) a list of 2-tuples, which are the x,y coordinates of the 
+#               Voronoi diagram vertices
+#           (2) a list of 3-tuples (a,b,c) which are the equations of the
+#               lines in the Voronoi diagram: a*x + b*y = c
+#           (3) a list of 3-tuples, (l, v1, v2) representing edges of the 
+#               Voronoi diagram.  l is the index of the line, v1 and v2 are
+#               the indices of the vetices at the end of the edge.  If 
+#               v1 or v2 is -1, the line extends to infinity.
+#
+#   computeDelaunayTriangulation(points):
+#
+#        Takes a list of point objects (which must have x and y fields).
+#        Returns a list of 3-tuples: the indices of the points that form a
+#        Delaunay triangle.
+#
+#############################################################################
+import math
+import sys
+import getopt
+TOLERANCE = 1e-9
+BIG_FLOAT = 1e38
+
+#------------------------------------------------------------------
+class Context( object ):
+    def __init__(self):
+        self.doPrint = 0
+        self.debug   = 0
+        self.plot    = 0
+        self.triangulate = False
+        self.vertices  = []    # list of vertex 2-tuples: (x,y)
+        self.lines     = []    # equation of line 3-tuple (a b c), for the equation of the line a*x+b*y = c  
+        self.edges     = []    # edge 3-tuple: (line index, vertex 1 index, vertex 2 index)   if either vertex index is -1, the edge extends to infiinity
+        self.triangles = []    # 3-tuple of vertex indices
+#        self.extra_edges = []  # list of additional vertex 2-tubles (x,y) based on bounded voronoi tesselation
+#        self.set_bounds(None)
+#        self.use_bound = False
+        self.xmin = self.ymin = self.xmax = self.ymax = None
+
+    def circle(self,x,y,rad):
+        pass
+
+    def clip_line(self,edge,lid,rid):
+        pass
+        # here is where I will create false verticies if
+        # the voronoi line extends to infinity...
+        # the extra verticies will be added to the
+        # extra edges list as 2-tuples
+#        a,b,c = edge.a,edge.b,edge.c
+#        if lid == -1:
+#            x = self.xMin
+#            y = (c-a*x) / b
+#            if y < self.yMin or y > self.yMax:
+#                if y < self.yMin: y = self.yMin
+#                elif y > self.yMax: y = self.yMax
+#                x = (c-b*y) / a
+#            self.extra_edges.append((x,y))
+#            lid = -(len(self.extra_edges)-1)
+#        if rid == -1:
+#            x = self.xMax
+#            y = (c-a*x) / b
+#            if y < self.yMin or y > self.yMax:
+#                if y < self.yMin: y = self.yMin
+#                elif y > self.yMax: y = self.yMax
+#                x = (c-b*y) / a
+#            self.extra_edges.append((x,y))
+#            rid = -(len(self.extra_edges)-1)
+#        print lid,rid
+#        return (lid,rid)
+
+    def line(self,x0,y0,x1,y1):
+        pass
+
+    def outSite(self,s):
+        if(self.debug):
+            print "site (%d) at %f %f" % (s.sitenum, s.x, s.y)
+        elif(self.triangulate):
+            pass
+        elif(self.plot):
+            self.circle (s.x, s.y, 3) #cradius)
+        elif(self.doPrint):
+            print "s %f %f" % (s.x, s.y)
+
+    def outVertex(self,s):
+        self.vertices.append((s.x,s.y))
+        if s.x < self.xmin: self.xmin = s.x
+        elif s.x > self.xmax: self.xmax = s.x
+        if s.y < self.ymin: self.ymin = s.y
+        elif s.y > self.ymax: self.ymax = s.y
+        
+        if(self.debug):
+            print  "vertex(%d) at %f %f" % (s.sitenum, s.x, s.y)
+        elif(self.triangulate):
+            pass
+        elif(self.doPrint and not self.plot):
+            print "v %f %f" % (s.x,s.y)
+
+    def outTriple(self,s1,s2,s3):
+        self.triangles.append((s1.sitenum, s2.sitenum, s3.sitenum))
+        if(self.debug):
+            print "circle through left=%d right=%d bottom=%d" % (s1.sitenum, s2.sitenum, s3.sitenum)
+        elif(self.triangulate and self.doPrint and not self.plot):
+            print "%d %d %d" % (s1.sitenum, s2.sitenum, s3.sitenum)
+
+    def outBisector(self,edge):
+        self.lines.append((edge.a, edge.b, edge.c))
+        if(self.debug):
+            print "line(%d) %gx+%gy=%g, bisecting %d %d" % (edge.edgenum, edge.a, edge.b, edge.c, edge.reg[0].sitenum, edge.reg[1].sitenum)
+        elif(self.triangulate):
+            if(self.plot):
+                self.line(edge.reg[0].x, edge.reg[0].y, edge.reg[1].x, edge.reg[1].y)
+        elif(self.doPrint and not self.plot):
+            print "l %f %f %f" % (edge.a, edge.b, edge.c)
+
+    def outEdge(self,edge):
+        sitenumL = -1
+        if edge.ep[Edge.LE] is not None:
+            sitenumL = edge.ep[Edge.LE].sitenum
+        sitenumR = -1
+        if edge.ep[Edge.RE] is not None:
+            sitenumR = edge.ep[Edge.RE].sitenum
+            
+#        if sitenumL == -1 or sitenumR == -1 and self.use_bound:
+#            sitenumL,sitenumR = self.clip_line(edge,sitenumL,sitenumR)
+
+        self.edges.append((edge.edgenum,sitenumL,sitenumR))
+        if(not self.triangulate):
+            if self.plot:
+                self.clip_line(edge)
+            elif(self.doPrint): 
+                print "e %d" % edge.edgenum,
+                print " %d " % sitenumL,
+                print "%d" % sitenumR
+
+    def set_bounds(self,bounds):
+        if not bounds == None:
+            self.xmin = bounds.xmin
+            self.ymin = bounds.ymin
+            self.xmax = bounds.xmax
+            self.ymax = bounds.ymax
+        else:
+            self.xmin = self.ymin = self.xmax = self.ymax = None
+        
+
+#------------------------------------------------------------------
+def voronoi(siteList,context):
+    edgeList  = EdgeList(siteList.xmin,siteList.xmax,len(siteList))
+    priorityQ = PriorityQueue(siteList.ymin,siteList.ymax,len(siteList))
+    siteIter = siteList.iterator()
+    
+    bottomsite = siteIter.next()
+    context.outSite(bottomsite)
+    newsite = siteIter.next()
+    minpt = Site(-BIG_FLOAT,-BIG_FLOAT)
+    while True:
+        if not priorityQ.isEmpty():
+            minpt = priorityQ.getMinPt()
+
+        if (newsite and (priorityQ.isEmpty() or cmp(newsite,minpt) < 0)):
+            # newsite is smallest -  this is a site event
+            context.outSite(newsite)
+            
+            # get first Halfedge to the LEFT and RIGHT of the new site 
+            lbnd = edgeList.leftbnd(newsite) 
+            rbnd = lbnd.right                    
+            
+            # if this halfedge has no edge, bot = bottom site (whatever that is)
+            # create a new edge that bisects
+            bot  = lbnd.rightreg(bottomsite)     
+            edge = Edge.bisect(bot,newsite)      
+            context.outBisector(edge)
+            
+            # create a new Halfedge, setting its pm field to 0 and insert 
+            # this new bisector edge between the left and right vectors in
+            # a linked list
+            bisector = Halfedge(edge,Edge.LE)    
+            edgeList.insert(lbnd,bisector)       
+
+            # if the new bisector intersects with the left edge, remove 
+            # the left edge's vertex, and put in the new one
+            p = lbnd.intersect(bisector)
+            if p is not None:
+                priorityQ.delete(lbnd)
+                priorityQ.insert(lbnd,p,newsite.distance(p))
+
+            # create a new Halfedge, setting its pm field to 1
+            # insert the new Halfedge to the right of the original bisector
+            lbnd = bisector
+            bisector = Halfedge(edge,Edge.RE)     
+            edgeList.insert(lbnd,bisector)        
+
+            # if this new bisector intersects with the right Halfedge
+            p = bisector.intersect(rbnd)
+            if p is not None:
+                # push the Halfedge into the ordered linked list of vertices
+                priorityQ.insert(bisector,p,newsite.distance(p))
+            
+            newsite = siteIter.next()
+
+        elif not priorityQ.isEmpty():
+            # intersection is smallest - this is a vector (circle) event 
+
+            # pop the Halfedge with the lowest vector off the ordered list of 
+            # vectors.  Get the Halfedge to the left and right of the above HE
+            # and also the Halfedge to the right of the right HE
+            lbnd  = priorityQ.popMinHalfedge()      
+            llbnd = lbnd.left               
+            rbnd  = lbnd.right              
+            rrbnd = rbnd.right              
+            
+            # get the Site to the left of the left HE and to the right of
+            # the right HE which it bisects
+            bot = lbnd.leftreg(bottomsite)  
+            top = rbnd.rightreg(bottomsite) 
+            
+            # output the triple of sites, stating that a circle goes through them
+            mid = lbnd.rightreg(bottomsite)
+            context.outTriple(bot,top,mid)          
+
+            # get the vertex that caused this event and set the vertex number
+            # couldn't do this earlier since we didn't know when it would be processed
+            v = lbnd.vertex                 
+            siteList.setSiteNumber(v)
+            context.outVertex(v)
+            
+            # set the endpoint of the left and right Halfedge to be this vector
+            if lbnd.edge.setEndpoint(lbnd.pm,v):
+                context.outEdge(lbnd.edge)
+            
+            if rbnd.edge.setEndpoint(rbnd.pm,v):
+                context.outEdge(rbnd.edge)
+
+            
+            # delete the lowest HE, remove all vertex events to do with the 
+            # right HE and delete the right HE
+            edgeList.delete(lbnd)           
+            priorityQ.delete(rbnd)
+            edgeList.delete(rbnd)
+            
+            
+            # if the site to the left of the event is higher than the Site
+            # to the right of it, then swap them and set 'pm' to RIGHT
+            pm = Edge.LE
+            if bot.y > top.y:
+                bot,top = top,bot
+                pm = Edge.RE
+
+            # Create an Edge (or line) that is between the two Sites.  This 
+            # creates the formula of the line, and assigns a line number to it
+            edge = Edge.bisect(bot, top)     
+            context.outBisector(edge)
+
+            # create a HE from the edge 
+            bisector = Halfedge(edge, pm)    
+            
+            # insert the new bisector to the right of the left HE
+            # set one endpoint to the new edge to be the vector point 'v'
+            # If the site to the left of this bisector is higher than the right
+            # Site, then this endpoint is put in position 0; otherwise in pos 1
+            edgeList.insert(llbnd, bisector) 
+            if edge.setEndpoint(Edge.RE - pm, v):
+                context.outEdge(edge)
+            
+            # if left HE and the new bisector don't intersect, then delete 
+            # the left HE, and reinsert it 
+            p = llbnd.intersect(bisector)
+            if p is not None:
+                priorityQ.delete(llbnd);
+                priorityQ.insert(llbnd, p, bot.distance(p))
+
+            # if right HE and the new bisector don't intersect, then reinsert it 
+            p = bisector.intersect(rrbnd)
+            if p is not None:
+                priorityQ.insert(bisector, p, bot.distance(p))
+        else:
+            break
+
+    he = edgeList.leftend.right
+    while he is not edgeList.rightend:
+        context.outEdge(he.edge)
+        he = he.right
+
+#------------------------------------------------------------------
+def isEqual(a,b,relativeError=TOLERANCE):
+    # is nearly equal to within the allowed relative error
+    norm = max(abs(a),abs(b))
+    return (norm < relativeError) or (abs(a - b) < (relativeError * norm))
+
+#------------------------------------------------------------------
+class Site(object):
+    def __init__(self,x=0.0,y=0.0,sitenum=0):
+        self.x = x
+        self.y = y
+        self.sitenum = sitenum
+
+    def dump(self):
+        print "Site #%d (%g, %g)" % (self.sitenum,self.x,self.y)
+
+    def __cmp__(self,other):
+        if self.y < other.y:
+            return -1
+        elif self.y > other.y:
+            return 1
+        elif self.x < other.x:
+            return -1
+        elif self.x > other.x:
+            return 1
+        else:
+            return 0
+
+    def distance(self,other):
+        dx = self.x - other.x
+        dy = self.y - other.y
+        return math.sqrt(dx*dx + dy*dy)
+
+#------------------------------------------------------------------
+class Edge(object):
+    LE = 0
+    RE = 1
+    EDGE_NUM = 0
+    DELETED = {}   # marker value
+
+    def __init__(self):
+        self.a = 0.0
+        self.b = 0.0
+        self.c = 0.0
+        self.ep  = [None,None]
+        self.reg = [None,None]
+        self.edgenum = 0
+
+    def dump(self):
+        print "(#%d a=%g, b=%g, c=%g)" % (self.edgenum,self.a,self.b,self.c)
+        print "ep",self.ep
+        print "reg",self.reg
+
+    def setEndpoint(self, lrFlag, site):
+        self.ep[lrFlag] = site
+        if self.ep[Edge.RE - lrFlag] is None:
+            return False
+        return True
+
+    @staticmethod
+    def bisect(s1,s2):
+        newedge = Edge()
+        newedge.reg[0] = s1 # store the sites that this edge is bisecting
+        newedge.reg[1] = s2
+
+        # to begin with, there are no endpoints on the bisector - it goes to infinity
+        # ep[0] and ep[1] are None
+
+        # get the difference in x dist between the sites
+        dx = float(s2.x - s1.x)
+        dy = float(s2.y - s1.y)
+        adx = abs(dx)  # make sure that the difference in positive
+        ady = abs(dy)
+        
+        # get the slope of the line
+        newedge.c = float(s1.x * dx + s1.y * dy + (dx*dx + dy*dy)*0.5)  
+        if adx > ady :
+            # set formula of line, with x fixed to 1
+            newedge.a = 1.0
+            newedge.b = dy/dx
+            newedge.c /= dx
+        else:
+            # set formula of line, with y fixed to 1
+            newedge.b = 1.0
+            newedge.a = dx/dy
+            newedge.c /= dy
+
+        newedge.edgenum = Edge.EDGE_NUM
+        Edge.EDGE_NUM += 1
+        return newedge
+
+
+#------------------------------------------------------------------
+class Halfedge(object):
+    def __init__(self,edge=None,pm=Edge.LE):
+        self.left  = None   # left Halfedge in the edge list
+        self.right = None   # right Halfedge in the edge list
+        self.qnext = None   # priority queue linked list pointer
+        self.edge  = edge   # edge list Edge
+        self.pm     = pm
+        self.vertex = None  # Site()
+        self.ystar  = BIG_FLOAT
+
+    def dump(self):
+        print "Halfedge--------------------------"
+        print "left: ",    self.left  
+        print "right: ",   self.right 
+        print "edge: ",    self.edge  
+        print "pm: ",      self.pm    
+        print "vertex: ",
+        if self.vertex: self.vertex.dump()
+        else: print "None"
+        print "ystar: ",   self.ystar 
+
+
+    def __cmp__(self,other):
+        if self.ystar > other.ystar:
+            return 1
+        elif self.ystar < other.ystar:
+            return -1
+        elif self.vertex.x > other.vertex.x:
+            return 1
+        elif self.vertex.x < other.vertex.x:
+            return -1
+        else:
+            return 0
+
+    def leftreg(self,default):
+        if not self.edge: 
+            return default
+        elif self.pm == Edge.LE:
+            return self.edge.reg[Edge.LE]
+        else:
+            return self.edge.reg[Edge.RE]
+
+    def rightreg(self,default):
+        if not self.edge: 
+            return default
+        elif self.pm == Edge.LE:
+            return self.edge.reg[Edge.RE]
+        else:
+            return self.edge.reg[Edge.LE]
+
+
+    # returns True if p is to right of halfedge self
+    def isPointRightOf(self,pt):
+        e = self.edge
+        topsite = e.reg[1]
+        right_of_site = pt.x > topsite.x
+        
+        if(right_of_site and self.pm == Edge.LE): 
+            return True
+        
+        if(not right_of_site and self.pm == Edge.RE):
+            return False
+        
+        if(e.a == 1.0):
+            dyp = pt.y - topsite.y
+            dxp = pt.x - topsite.x
+            fast = 0;
+            if ((not right_of_site and e.b < 0.0) or (right_of_site and e.b >= 0.0)):
+                above = dyp >= e.b * dxp
+                fast = above
+            else:
+                above = pt.x + pt.y * e.b > e.c
+                if(e.b < 0.0):
+                    above = not above
+                if (not above):
+                    fast = 1
+            if (not fast):
+                dxs = topsite.x - (e.reg[0]).x
+                above = e.b * (dxp*dxp - dyp*dyp) < dxs*dyp*(1.0+2.0*dxp/dxs + e.b*e.b)
+                if(e.b < 0.0):
+                    above = not above
+        else:  # e.b == 1.0 
+            yl = e.c - e.a * pt.x
+            t1 = pt.y - yl
+            t2 = pt.x - topsite.x
+            t3 = yl - topsite.y
+            above = t1*t1 > t2*t2 + t3*t3
+        
+        if(self.pm==Edge.LE):
+            return above
+        else:
+            return not above
+
+    #--------------------------
+    # create a new site where the Halfedges el1 and el2 intersect
+    def intersect(self,other):
+        e1 = self.edge
+        e2 = other.edge
+        if (e1 is None) or (e2 is None):
+            return None
+
+        # if the two edges bisect the same parent return None
+        if e1.reg[1] is e2.reg[1]:
+            return None
+
+        d = e1.a * e2.b - e1.b * e2.a
+        if isEqual(d,0.0):
+            return None
+
+        xint = (e1.c*e2.b - e2.c*e1.b) / d
+        yint = (e2.c*e1.a - e1.c*e2.a) / d
+        if(cmp(e1.reg[1],e2.reg[1]) < 0):
+            he = self
+            e = e1
+        else:
+            he = other
+            e = e2
+
+        rightOfSite = xint >= e.reg[1].x
+        if((rightOfSite     and he.pm == Edge.LE) or
+           (not rightOfSite and he.pm == Edge.RE)):
+            return None
+
+        # create a new site at the point of intersection - this is a new 
+        # vector event waiting to happen
+        return Site(xint,yint)
+
+        
+
+#------------------------------------------------------------------
+class EdgeList(object):
+    def __init__(self,xmin,xmax,nsites):
+        if xmin > xmax: xmin,xmax = xmax,xmin
+        self.hashsize = int(2*math.sqrt(nsites+4))
+        
+        self.xmin   = xmin
+        self.deltax = float(xmax - xmin)
+        self.hash   = [None]*self.hashsize
+        
+        self.leftend  = Halfedge()
+        self.rightend = Halfedge()
+        self.leftend.right = self.rightend
+        self.rightend.left = self.leftend
+        self.hash[0]  = self.leftend
+        self.hash[-1] = self.rightend
+
+    def insert(self,left,he):
+        he.left  = left
+        he.right = left.right
+        left.right.left = he
+        left.right = he
+
+    def delete(self,he):
+        he.left.right = he.right
+        he.right.left = he.left
+        he.edge = Edge.DELETED
+
+    # Get entry from hash table, pruning any deleted nodes 
+    def gethash(self,b):
+        if(b < 0 or b >= self.hashsize):
+            return None
+        he = self.hash[b]
+        if he is None or he.edge is not Edge.DELETED:
+            return he
+
+        #  Hash table points to deleted half edge.  Patch as necessary.
+        self.hash[b] = None
+        return None
+
+    def leftbnd(self,pt):
+        # Use hash table to get close to desired halfedge 
+        bucket = int(((pt.x - self.xmin)/self.deltax * self.hashsize))
+        
+        if(bucket < 0): 
+            bucket =0;
+        
+        if(bucket >=self.hashsize): 
+            bucket = self.hashsize-1
+
+        he = self.gethash(bucket)
+        if(he is None):
+            i = 1
+            while True:
+                he = self.gethash(bucket-i)
+                if (he is not None): break;
+                he = self.gethash(bucket+i)
+                if (he is not None): break;
+                i += 1
+    
+        # Now search linear list of halfedges for the corect one
+        if (he is self.leftend) or (he is not self.rightend and he.isPointRightOf(pt)):
+            he = he.right
+            while he is not self.rightend and he.isPointRightOf(pt):
+                he = he.right
+            he = he.left;
+        else:
+            he = he.left
+            while (he is not self.leftend and not he.isPointRightOf(pt)):
+                he = he.left
+
+        # Update hash table and reference counts
+        if(bucket > 0 and bucket < self.hashsize-1):
+            self.hash[bucket] = he
+        return he
+
+
+#------------------------------------------------------------------
+class PriorityQueue(object):
+    def __init__(self,ymin,ymax,nsites):
+        self.ymin = ymin
+        self.deltay = ymax - ymin
+        self.hashsize = int(4 * math.sqrt(nsites))
+        self.count = 0
+        self.minidx = 0
+        self.hash = []
+        for i in range(self.hashsize):
+            self.hash.append(Halfedge())
+
+    def __len__(self):
+        return self.count
+
+    def isEmpty(self):
+        return self.count == 0
+
+    def insert(self,he,site,offset):
+        he.vertex = site
+        he.ystar  = site.y + offset
+        last = self.hash[self.getBucket(he)]
+        next = last.qnext
+        while((next is not None) and cmp(he,next) > 0):
+            last = next
+            next = last.qnext
+        he.qnext = last.qnext
+        last.qnext = he
+        self.count += 1
+
+    def delete(self,he):
+        if (he.vertex is not None):
+            last = self.hash[self.getBucket(he)]
+            while last.qnext is not he:
+                last = last.qnext
+            last.qnext = he.qnext
+            self.count -= 1
+            he.vertex = None
+
+    def getBucket(self,he):
+        bucket = int(((he.ystar - self.ymin) / self.deltay) * self.hashsize)
+        if bucket < 0: bucket = 0
+        if bucket >= self.hashsize: bucket = self.hashsize-1
+        if bucket < self.minidx:  self.minidx = bucket
+        return bucket
+
+    def getMinPt(self):
+        while(self.hash[self.minidx].qnext is None):
+            self.minidx += 1
+        he = self.hash[self.minidx].qnext
+        x = he.vertex.x
+        y = he.ystar
+        return Site(x,y)
+
+    def popMinHalfedge(self):
+        curr = self.hash[self.minidx].qnext
+        self.hash[self.minidx].qnext = curr.qnext
+        self.count -= 1
+        return curr
+
+
+#------------------------------------------------------------------
+class SiteList(object):
+    def __init__(self,pointList):
+        self.__sites = []
+        self.__sitenum = 0
+
+        self.__xmin = pointList[0].x()
+        self.__ymin = pointList[0].y()
+        self.__xmax = pointList[0].x()
+        self.__ymax = pointList[0].y()
+        for i,pt in enumerate(pointList):
+            self.__sites.append(Site(pt.x(),pt.y(),i))
+            if pt.x() < self.__xmin: self.__xmin = pt.x()
+            if pt.y() < self.__ymin: self.__ymin = pt.y()
+            if pt.x() > self.__xmax: self.__xmax = pt.x()
+            if pt.y() > self.__ymax: self.__ymax = pt.y()
+        self.__sites.sort()
+
+    def setSiteNumber(self,site):
+        site.sitenum = self.__sitenum
+        self.__sitenum += 1
+
+    class Iterator(object):
+        def __init__(this,lst):  this.generator = (s for s in lst)
+        def __iter__(this):      return this
+        def next(this): 
+            try:
+                return this.generator.next()
+            except StopIteration:
+                return None
+
+    def iterator(self):
+        return SiteList.Iterator(self.__sites)
+
+    def __iter__(self):
+        return SiteList.Iterator(self.__sites)
+
+    def __len__(self):
+        return len(self.__sites)
+
+    def _getxmin(self): return self.__xmin
+    def _getymin(self): return self.__ymin
+    def _getxmax(self): return self.__xmax
+    def _getymax(self): return self.__ymax
+    xmin = property(_getxmin)
+    ymin = property(_getymin)
+    xmax = property(_getxmax)
+    ymax = property(_getymax)
+
+
+#------------------------------------------------------------------
+def computeVoronoiDiagram( points ):
+    """ Takes a list of point objects (which must have x and y fields).
+        Returns a 3-tuple of:
+
+           (1) a list of 2-tuples, which are the x,y coordinates of the 
+               Voronoi diagram vertices
+           (2) a list of 3-tuples (a,b,c) which are the equations of the
+               lines in the Voronoi diagram: a*x + b*y = c
+           (3) a list of 3-tuples, (l, v1, v2) representing edges of the 
+               Voronoi diagram.  l is the index of the line, v1 and v2 are
+               the indices of the vetices at the end of the edge.  If 
+               v1 or v2 is -1, the line extends to infinity.
+    """
+    siteList = SiteList( points )
+    context  = Context()
+    context.set_bounds( siteList )
+    voronoi( siteList, context )
+    return ( context.vertices, context.lines, context.edges, (context.xmin,context.ymin,context.xmax,context.ymax))
+
+#------------------------------------------------------------------
+def computeDelaunayTriangulation( points ):
+    """ Takes a list of point objects (which must have x and y fields).
+        Returns a list of 3-tuples: the indices of the points that form a
+        Delaunay triangle.
+    """
+    siteList = SiteList( points )
+    context  = Context()
+    context.triangulate = True
+    voronoi( siteList, context )
+    return context.triangles
+
+#-----------------------------------------------------------------------------
+if __name__=="__main__":
+    try:
+        optlist,args = getopt.getopt(sys.argv[1:],"thdp")
+    except getopt.GetoptError:
+        usage()
+        sys.exit(2)
+      
+    doHelp = 0
+    c = Context()
+    c.doPrint = 1
+    for opt in optlist:
+        if opt[0] == "-d":  c.debug = 1
+        if opt[0] == "-p":  c.plot  = 1
+        if opt[0] == "-t":  c.triangulate = 1
+        if opt[0] == "-h":  doHelp = 1
+
+    if not doHelp:
+        pts = []
+        fp = sys.stdin
+        if len(args) > 0:
+            fp = open(args[0],'r')
+        for line in fp:
+            fld = line.split()
+            x = float(fld[0])
+            y = float(fld[1])
+            pts.append(Site(x,y))
+        if len(args) > 0: fp.close()
+
+    if doHelp or len(pts) == 0:
+        usage()
+        sys.exit(2)
+
+    sl = SiteList(pts)
+    voronoi(sl,c)
+



More information about the QGIS-commit mailing list