source: inundation/ga/storm_surge/pmesh/pmesh.py @ 1470

Last change on this file since 1470 was 1421, checked in by duncan, 19 years ago

speed up the drawing of alpha boundaries

File size: 75.6 KB
Line 
1
2import  Pmw, AppShell, math, time, string, marshal
3from toolbarbutton import ToolBarButton
4import tkFileDialog
5from   tkSimpleDialog import Dialog
6import mesh
7from Tkinter import  FALSE,TRUE, Frame,X, LEFT,YES,BOTH,ALL,Widget,CURRENT, Label,W, Entry, E, StringVar, END, Checkbutton, Radiobutton, IntVar, DISABLED, NORMAL
8#from cursornames import TLC,TRC, BLC, BRC, TS, RS, LS, BS
9from tkMessageBox import showerror, _show, QUESTION,YESNOCANCEL
10import types
11import visualmesh
12import os
13import profile
14import load_mesh.loadASCII
15
16# CONSTANTS
17VERT_SELECT_ADDING_SEG_COLOR = 'orange'
18SELECT_COLOR = 'red'
19SEG_COLOUR = 'blue'
20TRIANGLE_COLOUR = 'green'
21APPLICATION_NAME = 'Pmesh'
22SET_COLOUR = 'red'
23DEFAULT_ATTRIBUTE = 'elevation'
24
25#for alpha shapes
26NO_SELECTION = 0
27AUTO = 1
28SET_ALPHA = 2
29
30
31class Draw(AppShell.AppShell):
32    usecommandarea = 1
33    appname        = APPLICATION_NAME
34    frameWidth     = 840
35    frameHeight    = 600
36   
37   
38    def createButtons(self):
39        """
40        Add buttons to the bottom of the GUI
41        """
42        self.buttonAdd('Postscript',
43              helpMessage='Save current drawing (as PostScript)',
44              statusMessage='',
45              command=self.ipostscript)
46        self.buttonAdd('Clear', helpMessage='Delete the mesh',
47              statusMessage='', command=self.clearMesh)
48        self.buttonAdd('Close', helpMessage='Close Screen',
49              statusMessage='', command=self.close)
50       
51    def createBase(self):
52        """
53        Create the GUI framework.  Set up the GUI
54        """
55        self.toolbar = self.createcomponent('toolbar', (), None,
56                  Frame, (self.interior(),), background="gray90")
57        self.toolbar.pack(fill=X)
58
59        self.scrolledcanvas =  self.createcomponent('ScrolledCanvas', (), None,
60                                       Pmw.ScrolledCanvas, (self.interior(),)
61                                       ,borderframe = 1
62                                       ,labelpos = 'n'
63                                       )
64        self.scrolledcanvas.configure(hscrollmode = 'dynamic')
65        self.scrolledcanvas.configure(vscrollmode = 'dynamic')
66        self.scrolledcanvas.pack(side=LEFT, expand=YES, fill=BOTH)
67        self.canvas = self.scrolledcanvas.component('canvas')
68        self.canvas.configure( background="white" )
69       
70        self.canvas.pack(side=LEFT, expand=YES, fill=BOTH)
71
72        Widget.bind(self.canvas, "<Button-1>", self.mouseDown)
73        Widget.bind(self.canvas, "<Button3-ButtonRelease>", self.rightMouseUp)
74        Widget.bind(self.canvas, "<Button2-ButtonRelease>",self.DeleteSelectedMeshObject)
75        # "<Delete>" didn't work..
76        #Widget.bind(self.canvas, "<Delete>", self.DeleteSelectedMeshObject)
77
78        #self.root.bind("<KeyPress>", self.setRegular)
79        #self.root.bind("<KeyRelease>", self.setRegular)
80       
81        self.scrolledcanvas.resizescrollregion()
82
83#     def setRegular(self, event):
84#         if event.type == '2' and event.keysym == 'Shift_L':
85#             self.regular = TRUE
86#         else:
87#             self.regular = FALSE
88
89    def createMenus(self):
90        """
91        Add menus to the top of the GUI
92        """
93        self.menuBar.deletemenuitems('File',0)
94        self.menuBar.addmenuitem('File', 'command', 'New mesh',
95                                 label='New', command=self.clearMesh)
96        self.menuBar.addmenuitem('File', 'command', 'Open mesh',
97                                 label='Open...', command=self.importFile)
98        self.menuBar.addmenuitem('File', 'command', 'Save mesh',
99                                 label='Save', command=self.saveDrawing)
100        self.menuBar.addmenuitem('File', 'command', 'Save mesh',
101                                 label='SaveAs...', command=self.saveAsDrawing)
102       
103        self.menuBar.addmenuitem('File', 'separator')
104        self.menuBar.addmenuitem('File', 'command',
105                                 'Add ungenerated file from arcGIS',
106                                 label='Add ungenerated file...',
107                                 command=self.ImportUngenerate)
108       
109        self.menuBar.addmenuitem('File', 'command',
110                                 'Export ASCII obj',
111                                 label='Export ASCII obj',
112                                 command=self.exportObj)
113       
114        self.menuBar.addmenuitem('File', 'command',
115                                 'Export ASCII segment outline',
116                                 label='Export ASCII segment outline...',
117                                 command=self.exportASCIIsegmentoutlinefile)
118       
119        self.menuBar.addmenuitem('File', 'command',
120                                 'Export ASCII xya file',
121                                 label='Export ASCII xya file...',
122                                 command=self.exportPointsFile)
123       
124        self.menuBar.addmenuitem('File', 'command',
125                                 'add Segments to connect all vertices'  ,
126                                 label='join vertices',
127                                 command=self.joinVertices)
128        self.menuBar.addmenuitem('File', 'command',
129                                 'add Segments to form alpha shape'  ,
130                                 label='Auto segment',
131                                 command=self.autoSegment)
132        self.menuBar.addmenuitem('File', 'command',
133                           'modify the alpha boundary by applying filters',
134                                 label='filter alpha boundary',
135                                 command=self.autoSegmentFilter)
136        self.menuBar.addmenuitem('File', 'command', 'Normalise mesh',
137                                 label='Normalise mesh', command=self.normaliseMesh)
138        self.menuBar.addmenuitem('File', 'command', 'Normalise mesh for glutobj',
139                                 label='Normalise mesh for glutobj', command=self.normalise4ObjMesh)
140        self.menuBar.addmenuitem('File', 'separator')
141        self.menuBar.addmenuitem('File', 'command', '',
142                                 label='Print geo reference', command=self.printGeoReference)
143        self.menuBar.addmenuitem('File', 'separator')
144        self.menuBar.addmenuitem('File', 'command', 'Exit program',
145                                 label='Exit', command=self.quit)
146
147    def createTools(self):
148        """
149        Add buttons to the top of the GUI
150        """
151        self.mouseDownFunc = {}
152        self.modeClass = {}
153        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif',
154                      width=10, state='disabled')
155        for key, balloon, mouseDownFunc, Mode in [
156            ('pointer','Edit drawing eventually.  Right now this does nothing', self.drag, None)
157            ,('vertex',    'Vertex mode', self.drawVertex, mesh.Vertex)
158            ,('segment', 'Segment mode',self.selectSegmentPoint, mesh.Segment)
159            ,('hole', 'hole mode',self.drawHole, mesh.Hole)
160            ,('region', 'region mode',self.drawRegion, mesh.Region)
161            ]:
162            t = ToolBarButton(self, self.toolbar, key, '%s.gif' % key,
163                          command=self.selectFunc, balloonhelp=balloon,
164                               statushelp='')
165            t.cycle("DrawMode")
166            if key == 'pointer': #FIXME- this is specified in line 1062 as well
167                                 # self.selectFunc('pointer')
168                self.curFunc  = self.drawVertex
169                t.setInitialSunkenButton("DrawMode")
170            self.modeClass[key] = Mode
171            # for actions that occur when the mouse goes down
172            self.mouseDownFunc[key] = mouseDownFunc
173         
174    def createZooms(self):
175        """
176        Add zoom buttons to the top of the GUI
177        """
178        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif', width=10,
179                      state='disabled')
180        zoom = '0.5'
181        ToolBarButton(self, self.toolbar, zoom, 'zoom%s.gif' %
182                      zoom, command=self.selectZoom,
183                      balloonhelp='*%s zoom' % zoom,
184                      statushelp='')
185           
186        ToolBarButton(self, self.toolbar,'1.0', 'zoomToMesh.gif',
187                      command=self.ResizeToFitWrapper,
188                      balloonhelp='Zooms to mesh size',
189                      statushelp='')
190        zoom = '2'
191        ToolBarButton(self, self.toolbar, zoom, 'zoom%s.gif' %
192                      zoom, command=self.selectZoom,
193                      balloonhelp='*%s zoom' % zoom,
194                      statushelp='')
195
196    def createEdits(self):
197        """
198        Add Edit buttons to the top of the GUI
199        """
200        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif', width=10,
201                      state='disabled')
202        for key, func, balloon in [
203                ('addVertex', self.windowAddVertex, 'add Vertex'),
204                ('edit', self.windowEdit, 'edit selected object'),
205                ('default', self.windowDefault, 'set default value for selected mode'),
206                ('joinVer', self.joinVerticesButton, 'add Segments to connect all vertices'),     
207             #   ('autoSegHull', self.autoSegmentHullButton, 'add Segments to form alpha shape, using Hull'), 
208             #   ('autoSeg', self.autoSegmentButton, 'add Segments to form alpha shape'),
209                ('autoSegGiveAlpha', self.autoSegmentGiveAlphaButton, 'add Segments to form alpha shape, specify alpha'),
210                ('meshGen', self.windowMeshGen, 'Generate Mesh')]:
211            ToolBarButton(self, self.toolbar, key, '%s.gif' % key,
212                          command=func, balloonhelp=balloon,
213                               statushelp='' )
214
215
216
217    def createSetTools(self):
218        """
219        Add set tool buttons to the top of the GUI
220        """
221        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif', width=10,
222                      state='disabled')
223        for key, func, balloon in [
224                ('threshold', self.threshold, 'threshold the set'),
225                ('Courant_threshold', self.Courant_threshold, 'Courant_threshold the set'),
226                ('gradient_threshold', self.gradient_threshold, 'gradient_threshold the set'),
227                ('smooth', self.smooth_polySet, 'smooth the polygons'),
228                ('polyset', self.triangles_to_polySet, 'make a poly set out of selected triangles')]:     
229                #('refineSet', self.refineSet, 'Refine the set')]:
230            ToolBarButton(self, self.toolbar, key, '%s.gif' %key,
231                          command=func, balloonhelp=balloon,
232                               statushelp='' )
233
234    def createSetIcons(self):
235        """
236        Add Edit buttons to the top of the GUI
237        """
238        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif', width=10,
239                      state='disabled')
240        for key, func, balloon in [
241                ('selectAllTriangles', self.selectAllTriangles, 'select all'),
242                ('none', self.clearSelection, 'clear selection')]:
243            ToolBarButton(self, self.toolbar, key, '%s.gif' %key,
244                          command=func, balloonhelp=balloon,
245                               statushelp='' )
246
247    def createVisualiseIcons(self):
248        """
249        Add Edit buttons to the top of the GUI
250        """
251        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif', width=10,
252                      state='disabled')
253        for key, func, balloon in [
254                ('visualise', self.visualise, 'Visualise mesh triangles'),
255                ('unvisualise', self.unvisualise, 'Do not visualise mesh triangles (for large meshes)')]:
256            ToolBarButton(self, self.toolbar, key, '%s.gif' %key,
257                          command=func, balloonhelp=balloon,
258                               statushelp='' )
259
260
261    def refineSet(self,parent):
262        self.mesh.refineSet(self.selSet)
263        self.visualiseMesh(self.mesh)
264
265
266    def setStructureNumber(self,parent):
267        dialog =  setStructureNumberDialog(self.canvas)
268        if dialog.numberOK:
269            self.structureSize = dialog.number
270
271    def erode(self, parent):
272#Not implimented
273        self.canvas.delete(ALL)
274        self.mesh.erode(self.selSet,structureSize=self.structureSize)
275        self.visualiseMesh(self.mesh)
276
277
278    def dilate(self, parent):
279#Not implimented
280        self.canvas.delete(ALL)
281        self.mesh.dilate(self.selSet,structureSize=self.structureSize)
282        self.visualiseMesh(self.mesh)
283
284    def general_threshold(self,parent,function,function_description):
285        """
286        add a vertex using a window and entering x y values.
287
288        the parent attribute isn't used by this function.
289        need to userstand toolbarbutton.py to know how to
290        get rid of it.
291        """
292        if self.selSet == 'None':
293            self.selectAllTriangles(parent)
294
295        dialog = GeneralThresholdDialog(self.canvas,self.mesh.attributeTitles,function_description)
296        if dialog.minmaxValuesOk:
297            self.canvas.delete(ALL)
298            min = dialog.min
299            max = dialog.max
300            attribute_name = dialog.attribute_name
301            self.mesh.general_threshold(self.selSet,min=min,max=max,attribute_name = attribute_name,function=function)
302            self.visualiseMesh(self.mesh)
303
304    def threshold(self, parent):
305        """
306        add a vertex using a window and entering x y values.
307
308        the parent attribute isn't used by this function.
309        need to userstand toolbarbutton.py to know how to
310        get rid of it.
311        """
312        function = self.mesh.av_att
313        function_description = 'average attribute of triangle'
314        self.general_threshold(parent,function,function_description)
315
316
317    def Courant_threshold(self, parent):
318        """
319        add a vertex using a window and entering x y values.
320
321        the parent attribute isn't used by this function.
322        need to userstand toolbarbutton.py to know how to
323        get rid of it.
324        """
325        function = self.mesh.Courant_ratio
326        function_description = 'average attribute/area of triangle'
327        self.general_threshold(parent,function,function_description)
328
329    def gradient_threshold(self, parent):
330        """
331        add a vertex using a window and entering x y values.
332
333        the parent attribute isn't used by this function.
334        need to userstand toolbarbutton.py to know how to
335        get rid of it.
336        """
337        function = self.mesh.Gradient
338        function_description = 'average gradient of triangle'
339        self.general_threshold(parent,function,function_description)
340
341    def smooth_polySet(self,parent):
342        dialog = SmoothDialog(self.canvas)
343        if dialog.valueOK:
344            min_radius = dialog.min_radius
345            self._smooth_polySet(min_radius)
346
347    def _smooth_polySet(self,min_radius):
348        userVertices,userSegments,alphaSegments = \
349            self.mesh.smooth_polySet(min_radius=min_radius)
350
351        self.mesh.userVertices=[]
352        self.mesh.userSegments=[]
353        self.mesh.alphaSegments=[]
354        self.canvas.delete(ALL)
355        event = None
356        print 'len(userVertices.keys())'
357        print len(userVertices.keys())
358        print 'len(userSegments.keys())'
359        print len(userSegments.keys())
360        print 'len(alphaSegments.keys())'
361        print len(alphaSegments.keys())
362
363        #######
364        point_keys = {}
365        for vert in userVertices.keys():
366            assert not point_keys.has_key((vert.x,vert.y))
367            point_keys[(vert.x,vert.y)]=vert
368        assert len(point_keys.keys())==len(userVertices.keys())
369        #######
370
371        for v in userVertices.keys():
372            x = v.x*self.SCALE
373            y = v.y*self.SCALE
374            userVertices[(v.x,v.y)]=self.drawVertex(x,y,event)
375
376        for line in userSegments.keys():
377            v0 = userVertices[line[0]]
378            v1 = userVertices[line[1]]
379            segment = self.drawSegment(v0,v1)
380            segment.set_tag(userSegments[line].tag)
381
382        for line in alphaSegments.keys():
383            v0 = userVertices[line[0]]
384            v1 = userVertices[line[1]]
385            segment = self.drawSegment(v0,v1)
386            segment.set_tag(alphaSegments[line].tag)
387        self.visualiseMesh(self.mesh)
388
389
390    def triangles_to_polySet(self,parent):
391        userVertices,userSegments,alphaSegments = \
392            self.mesh.triangles_to_polySet(self.selSet)
393
394        self.mesh.userVertices=[]
395        self.canvas.delete(ALL)
396
397        event = None
398        print 'len(userVertices.keys())'
399        print len(userVertices.keys())
400        print 'len(userSegments.keys())'
401        print len(userSegments.keys())
402        print 'len(alphaSegments.keys())'
403        print len(alphaSegments.keys())
404
405
406        #######
407        point_keys = {}
408        for vert in userVertices.keys():
409            assert not point_keys.has_key((vert.x,vert.y))
410            point_keys[(vert.x,vert.y)]=vert
411        assert len(point_keys.keys())==len(userVertices.keys())
412        #######
413
414        for v in userVertices.keys():
415            if userVertices[v] is True:
416                x = v.x*self.SCALE
417                y = v.y*self.SCALE
418                userVertices[(v.x,v.y)]=self.drawVertex(x,y,event)
419
420        for line in userSegments.keys():
421            v0 = userVertices[line[0]]
422            v1 = userVertices[line[1]]
423            segment = self.drawSegment(v0,v1)
424            segment.set_tag(userSegments[line].tag)
425
426        for line in alphaSegments.keys():
427            v0 = userVertices[line[0]]
428            v1 = userVertices[line[1]]
429            segment = self.drawSegment(v0,v1)
430            segment.set_tag(alphaSegments[line].tag)
431        self.visualiseMesh(self.mesh)
432        #self.smooth_polySet(parent)
433
434    def selectTriangles(self,setName):
435        """
436        """
437        self.canvas.delete(ALL)
438        self.selSet = setName
439        self.visualiseMesh(self.mesh)
440
441    def selectAllTriangles(self,parent):
442        """
443        selected all triangles in the mesh
444        """
445        self.canvas.delete(ALL)
446        self.selSet = self.mesh.selectAllTriangles()
447        self.visualiseMesh(self.mesh)
448
449    def clearSelection(self,parent):
450    #FIXME looks like self.clearSelections - change name (Peter)
451        """
452        """
453        self.canvas.delete(ALL)
454        self.selSet = self.mesh.clearSelection()
455        self.visualiseMesh(self.mesh)
456
457    def visualise(self,parent):
458        self.canvas.delete(ALL)
459        self.Visualise = True
460        self.visualiseMesh(self.mesh)
461
462    def unvisualise(self,parent):
463        self.canvas.delete(ALL)
464        self.Visualise = False
465        self.visualiseMesh(self.mesh)
466
467    def createMesh(self):
468        """
469        Build the data structures for storing the mesh objects
470        """
471        self.mesh = mesh.Mesh()
472       
473        self.Vertices = visualmesh.vPoints(mesh.Vertex)
474        self.Segments = visualmesh.vSegments(mesh.Segment)
475        self.Holes = visualmesh.vPoints(mesh.Hole)
476        self.Regions = visualmesh.vRegions(mesh.Region)
477        self.UserMesh = visualmesh.vMesh([self.Vertices,self.Segments,self.Holes,self.Regions])
478       
479        self.Triangles = visualmesh.vTriangles(mesh.Triangle)
480        self.selSet='None'
481
482
483    def deleteMesh(self):
484        """
485        Delete the data structures for storing the mesh objects
486        """
487        self.mesh = None
488        self.Vertices = None
489        self.Segments = None
490        self.Triangles = None
491       
492    def addVertsAndSegs(self):
493        """
494        Automatically add some verts and segs to the mesh.Used in Debugging
495        """
496        v1 = self.drawVertex(0,0,None)
497        v2 = self.drawVertex(50,2,None)
498        v3 = self.drawVertex(70,30,None)
499        v4 = self.drawVertex(25,50,None)
500        v5 = self.drawVertex(-10,20,None)
501        #v5 = self.drawVertex(25,50,None)
502        s1 = self.drawSegment(v1,v2)
503        s1.set_tag("s1")
504        s2 = self.drawSegment(v2,v3)
505        s2.set_tag("s2")
506        s3 = self.drawSegment(v3,v4)
507        s3.set_tag("s3")
508        s4 = self.drawSegment(v4,v5)
509        s4.set_tag("s4")
510        s5 = self.drawSegment(v1,v5)
511        s5.set_tag("s5")
512
513        x_origin = 10
514        y_origin = 20
515        r = 10
516        pi = math.pi
517        num_of_cuts = 100
518        cuts = []
519        factor = 2* math.pi/num_of_cuts
520        for cut in range(num_of_cuts):
521             cuts.append(cut*factor)
522       
523        for radius in cuts:
524            x = x_origin + r * math.cos(radius)
525            y = y_origin + r * math.sin(radius)
526            v = self.drawVertex(x,y,None)
527            if not radius == 0.0:   # FIXME
528                self.drawSegment(v,v_old)
529            else:
530                v_first = v
531            v_old = v
532        self.drawSegment(v,v_first)
533        region = self.drawRegion(x_origin, y_origin, 0)
534        region.setTag("setheight5")
535
536       
537       
538        x_origin = 30
539        y_origin = 30
540        r = 5
541        pi = math.pi
542        num_of_cuts = 100
543        cuts = []
544        factor = 2* math.pi/num_of_cuts
545        for cut in range(num_of_cuts):
546             cuts.append(cut*factor)
547       
548        for radius in cuts:
549            x = x_origin + r * math.cos(radius)
550            y = y_origin + r * math.sin(radius)
551            v = self.drawVertex(x,y,None)
552            if not radius == 0.0:   # FIXME
553                self.drawSegment(v,v_old)
554            else:
555                v_first = v
556            v_old = v
557        self.drawSegment(v,v_first)
558        region = self.drawRegion(x_origin, y_origin, 0)
559        region.setTag("setheight10")
560           
561        #Since the new vertex may be off screen
562        self.scrolledcanvas.resizescrollregion()
563
564        # generate the mesh
565        minAngle = 30.0
566        numTriangles = 20000
567        self.clearSelections()
568        self.canvas.delete(ALL)
569        self.mesh = self.MeshGenAreaNumTriangles (minAngle,
570                                          numTriangles,
571                                          self.mesh)
572        self.UserMeshChanged = False
573        self.visualiseMesh(self.mesh)
574        print "Mesh Generation finished"
575           
576    def selectFunc(self, tag):
577        """
578        Change the current mode class
579        When changing from one mode to another
580        """
581        self.mouseDownCurFunc = self.mouseDownFunc[tag]
582        self.curModeClass = self.modeClass[tag]
583        self.clearSelections()
584        self.canvas.config(cursor='arrow')
585#        I can make it arrow, but it will change back to pointer, after
586#        adding an object
587#        if self.curFunc == self.func['pointer']:
588#            self.canvas.config(cursor='arrow')
589#         else:
590#             self.canvas.config(cursor='crosshair')
591
592    def clearSelections(self):
593        """
594        deselect objects that have been selected
595        """
596        if self.selMeshObject:
597            self.deselectMeshObject(self.selMeshObject, self.selMeshTag)       
598        if self.selVertex:
599            self.deselectVertex(self.selVertex, self.selVertexTag)
600         
601       
602    def selectZoom(self, tag):
603        """
604        Zoom in or out of the current mesh view
605        """
606        fraction = string.atof(tag)
607        self.SCALE *= fraction
608        self.scrolledcanvas.scale(ALL, 0, 0, fraction, fraction)
609
610        # Redraw all of the vertices, holes and regions,
611        #so the squares representing vertices
612        # don't get bigger
613        vertices = self.mesh.getUserVertices()
614        holes = self.mesh.getHoles()
615        regions = self.mesh.getRegions()
616        MeshObjects  = vertices + holes + regions
617
618        # make a list of tags to delete
619        guiIDs = [getattr(MeshObjects[i],'guiID') for i in xrange(len(MeshObjects))]
620        apply(self.canvas.delete, guiIDs)
621        for obj in MeshObjects:
622            if self.selVertex == obj:
623                obj.draw(self.canvas,obj.guiID,  scale =self.SCALE ,colour= VERT_SELECT_ADDING_SEG_COLOR)
624            elif self.selMeshObject == obj:
625                obj.draw(self.canvas,obj.guiID,  scale =self.SCALE ,colour= SELECT_COLOR)
626            else:
627                obj.draw(self.canvas,obj.guiID,  scale =self.SCALE ) 
628        top, bottom = self.scrolledcanvas.xview()
629        xcenter  = (top + bottom)/2
630        xdiff =  xcenter - top 
631        xcnew = xcenter - xdiff/fraction
632       
633        top, bottom = self.scrolledcanvas.yview()
634        ycenter = (top + bottom)/2
635        ydiff = ycenter - top
636        ycnew = ycenter - ydiff/fraction
637       
638        self.scrolledcanvas.resizescrollregion()
639        # update so the moveto calls will work...
640        self.scrolledcanvas.update()
641        # but calling update now does make things jerky
642        self.canvas.xview_moveto(xcnew)
643        self.canvas.yview_moveto(ycnew)
644       
645   
646    def windowAddVertex (self, parent):
647        """
648        add a vertex using a window and entering x y values.
649
650        the parent attribute isn't used by this function.
651        need to userstand toolbarbutton.py to know how to
652        get rid of it.
653        """
654       
655        dialog = AddVertexDialog(self.canvas)
656        if dialog.xyValuesOk:
657            print dialog.x
658            print dialog.y
659            self.drawVertex(dialog.x*self.SCALE,dialog.y*self.SCALE,None)
660            #Since the new vertex may be off screen
661            self.ResizeToFit()
662        else:
663            print "bad values"
664   
665    def windowDefault (self, parent):
666        """
667       
668        the parent attribute isn't used by this function.
669        need to userstand toolbarbutton.py to know how to
670        get rid of it.
671        """
672        # self.UserMesh is a vMesh instance
673        self.UserMesh.defaultWindow(self.canvas, self.curModeClass)
674   
675    def windowEdit (self, parent):
676        """
677
678        the parent attribute isn't used by this function.
679        need to userstand toolbarbutton.py to know how to
680        get rid of it.
681        """
682        if self.selMeshObject:   
683            self.UserMeshChanged = self.UserMesh.editWindow(self.canvas,
684                                     self.selMeshObject,
685                                     self.UserMeshChanged)
686   
687   
688    def autoSegmentHullButton (self, parent):
689        self.autoSegment()
690 
691    def autoSegmentHull (self):
692        """
693        add Segments to bound all vertices
694       
695        the parent attribute isn't used by this function.
696        need to userstand toolbarbutton.py to know how to
697        get rid of it.
698        """
699        if len(self.mesh.getUserVertices()) >= 3:
700            newsegs = self.mesh.autoSegment()
701            for segment in newsegs:
702                self.serial +=1
703                self.uniqueID = 'M*%d' % self.serial
704                self.Segments.visualise(segment,
705                                        self.uniqueID,
706                                        self.canvas,
707                                        self.SCALE)
708        else:
709            showerror('pMesh',
710                      'Three or more vetices are needed to be able to autosegment.')
711 
712    def autoSegmentButton (self, parent):
713        self.autoSegment()
714
715       
716    def autoSegmentGiveAlphaButton (self, parent):
717        dialog = AutoSegmentDialog(self.canvas, self.meshLastAlpha)
718        if dialog.use_optimum.get() == SET_ALPHA:
719            if dialog.alphaValueOk:
720                self.autoSegment(alpha = dialog.alpha,
721                                 raw_boundary=dialog.raw_boundary.get(),
722                                 remove_holes=dialog.remove_holes.get(),
723                                 smooth_indents=dialog.smooth_indents.get(),
724                                 expand_pinch=dialog.expand_pinch.get())
725            else:
726                 showerror('pMesh',
727                      'Bad alpha value.')
728        else:
729            self.autoSegment(raw_boundary=dialog.raw_boundary.get(),
730                             remove_holes=dialog.remove_holes.get(),
731                             smooth_indents=dialog.smooth_indents.get(),
732                             expand_pinch=dialog.expand_pinch.get())
733           
734       
735    def autoSegment (self, alpha = None,
736                                 raw_boundary=True,
737                                 remove_holes=False,
738                                 smooth_indents=False,
739                                 expand_pinch=False ):
740        """
741        add Segments to bound all vertices
742       
743        """
744        if len(self.mesh.getUserVertices()) >= 3:
745            newsegs, ObjectsToVisuallyDelete, self.meshLastAlpha = \
746                     self.mesh.autoSegment(alpha=alpha,
747                                           remove_holes=remove_holes,
748                                           smooth_indents=smooth_indents,
749                                           expand_pinch=expand_pinch)
750            #print "newsegs",newsegs
751            #print "ObjectsToVisuallyDelete",ObjectsToVisuallyDelete
752           
753            for drawOb in ObjectsToVisuallyDelete:
754                    self.UserMesh.unvisualise(drawOb, self.canvas)
755               
756            for segment in newsegs:
757                self.serial +=1
758                self.uniqueID = 'M*%d' % self.serial
759                self.Segments.visualise(segment,
760                                        self.uniqueID,
761                                        self.canvas,
762                                        self.SCALE)
763           
764        else:
765            showerror('pMesh',
766                      'Three or more vetices are needed to be able to autosegment.')
767
768
769    def autoSegmentFilter (self):
770        dialog = AutoSegmentFilterDialog(self.canvas)
771        newsegs, ObjectsToVisuallyDelete, self.meshLastAlpha = \
772                 self.mesh.autoSegmentFilter(raw_boundary=dialog.raw_boundary.get(),
773                             remove_holes=dialog.remove_holes.get(),
774                             smooth_indents=dialog.smooth_indents.get(),
775                             expand_pinch=dialog.expand_pinch.get())
776        #print "newsegs",newsegs
777        #print "ObjectsToVisuallyDelete",ObjectsToVisuallyDelete
778           
779        for drawOb in ObjectsToVisuallyDelete:
780            self.UserMesh.unvisualise(drawOb, self.canvas)
781               
782        for segment in newsegs:
783            self.serial +=1
784            self.uniqueID = 'M*%d' % self.serial
785            self.Segments.visualise(segment,
786                                    self.uniqueID,
787                                    self.canvas,
788                                    self.SCALE)
789       
790    def joinVerticesButton (self, parent):
791        self.joinVertices()
792       
793    def joinVertices (self):
794        """
795        add Segments to connect all vertices
796       
797        the parent attribute isn't used by this function.
798        need to userstand toolbarbutton.py to know how to
799        get rid of it.
800        """
801        if len(self.mesh.getUserVertices()) >= 3:
802            newsegs = self.mesh.joinVertices()
803            for segment in newsegs:
804                self.serial +=1
805                self.uniqueID = 'M*%d' % self.serial
806                self.Segments.visualise(segment,
807                                        self.uniqueID,
808                                        self.canvas,
809                                        self.SCALE)
810        else:
811            showerror('pMesh',
812                      'Three or more vetices are needed to be able to join vertices.')
813       
814    def windowMeshGen (self, parent):
815        """
816        The parent attribute isn't used by this function.
817        need to understand toolbarbutton.py to know how to
818        get rid of it.
819        """
820        # Put exceptions round things.
821        #catch failure in self.mesh.generateMesh
822        dialog = MeshGenDialog(self.canvas,
823                               self.MeshMinAngle,
824                               self.MeshMaxArea,
825                               self.MeshnumTriangles,
826                               self.MeshMaxAreaLast)
827       
828        if dialog.ValuesOk:
829            print dialog.minAngle
830            print dialog.maxArea
831           
832            self.clearSelections()
833            self.canvas.delete(ALL)
834            if dialog.goodMaxArea == True:
835                self.MeshMinAngle = dialog.minAngle
836                self.MeshMaxArea = dialog.maxArea
837                self.MeshMaxAreaLast = True
838               
839                self.mesh = self.MeshGenAreaAngle (dialog.minAngle,
840                                          dialog.maxArea,
841                                          self.mesh)
842            elif dialog.goodNumTriangles == True:
843                self.MeshMinAngle = dialog.minAngle
844                self.MeshnumTriangles  = dialog.numTriangles
845                self.MeshMaxAreaLast = False
846               
847                self.mesh = self.MeshGenAreaNumTriangles (dialog.minAngle,
848                                          dialog.numTriangles,
849                                          self.mesh)
850            else:
851                pass
852            print "userMeshChanged = False"
853            self.UserMeshChanged = False
854            self.visualiseMesh(self.mesh)
855            print "Mesh Generation finished"
856           
857    def MeshGenAreaAngle (self, minAngle, maxArea, mesh):
858        """
859        Generate a mesh, given a minAngle and max area
860        """
861        tempMesh = mesh
862        try:
863            tempMesh.generateMesh(mode = "pzq"+str(minAngle)
864                                  +"a"+str(maxArea)
865                                  +"a") #So areas for regions will be used
866        except AttributeError : # can't catch PyEval_RestoreThread
867            # This doesn't catch tempMesh.generateMesh failing
868            tempMesh = mesh
869        return tempMesh
870       
871
872    def MeshGenAreaNumTriangles (self, minAngle, numTriangles, mesh):
873        """
874        Generate a mesh, given a minAngle and rough # of triangles
875        """
876        #get big triangles
877        #calc area
878        #calc max triangle area
879        #
880        tempMesh = mesh
881        try:
882            tempMesh.generateMesh("pzq1")
883        except AttributeError : # can't catch PyEval_RestoreThread
884            # This doesn't catch tempMesh.generateMesh failing
885            pass
886        meshArea = 0
887        for triangle in tempMesh.getTriangulation():
888             meshArea += triangle.calcArea()
889        print "meshArea: ", meshArea
890
891        maxArea = meshArea/numTriangles
892
893       
894        return self.MeshGenAreaAngle (minAngle,
895                                      maxArea,
896                                      self.mesh)
897       
898    def mouseDown(self, event):
899        """
900        On a mouse down event, depending on the current state,
901        either add a vertex or a seg etc
902        """
903        self.curObject = None
904        self.lastx = self.startx = self.canvas.canvasx(event.x)
905        #The screen canvas has y 'flipped'.  -1* unflips it
906        self.lasty = self.starty = -1*self.canvas.canvasy(event.y)
907        print "----------------------"
908        self.mouseDownCurFunc( self.lastx,
909                               self.lasty,event) #!!! remove the event?
910                                                 # do last
911   
912    def rightMouseUp(self, event):
913        """
914        On a right mouse button up event select the nearest object.
915        """
916        found=False
917        if event.widget.find_withtag(CURRENT): # if there's a widget with a tag
918            [tag,string] = self.canvas.gettags(CURRENT) # get a list of them
919            print "tag",tag  #tags ('M*1008', 'current')
920            if tag[:2] == 'M*':   #!!! this can be removed when there are
921                #    only mesh objects on screen
922                #key, value = string.split(tag, '*')
923                objectID = tag
924                print "Found!! objectID:", objectID
925               
926                meshObjects = self.getAllUserMeshObjects()
927                # It may be a triangle, which is ignored
928                if meshObjects.hasKey(objectID):
929                    selMeshObject = meshObjects.getMeshObject(objectID)
930                    found = True
931                    print "Found! selMeshObject", selMeshObject
932                    #Only select one object at a time
933                    if self.selMeshObject:
934                        self.deselectMeshObject(self.selMeshObject, self.selMeshTag)
935                    self.selectMeshObject(selMeshObject,objectID)
936
937    def getAllUserMeshObjects(self):
938        return self.UserMesh
939       
940    def DeleteSelectedMeshObject(self, event):
941        """
942        if an object is selected, delete it.
943        """
944        if self.selMeshObject:
945            #an object is selected
946            #first deselect the vertex, for selecting a segment
947            if self.selVertex:
948                self.deselectVertex(self.selVertex, self.selVertexTag)
949            ObjectsToVisuallyDelete = self.mesh.deleteMeshObject (self.selMeshObject)
950            for drawOb in ObjectsToVisuallyDelete:
951                self.UserMesh.unvisualise(drawOb, self.canvas)
952               
953            self.selMeshObject = None
954            self.selMeshTag = None
955           
956    def selectMeshObject(self, meshObject, objectID):
957        """
958        selected a mesh object.
959        """
960        self.canvas.delete(objectID)
961        self.selMeshObject = meshObject
962        self.selMeshTag = objectID
963        meshObject.draw(self.canvas,objectID, scale =self.SCALE ,colour = SELECT_COLOR)
964   
965    def deselectMeshObject(self, meshObject, objectID):
966        """
967        deselected a mesh object.
968        """
969        self.canvas.delete(objectID)
970        self.selMeshObject = None
971        self.selMeshTag = None
972        if isinstance(meshObject, mesh.Segment):
973            meshObject.draw(self.canvas,objectID,
974                        scale =self.SCALE ,colour = SEG_COLOUR)
975        else:
976            meshObject.draw(self.canvas,objectID,
977                        scale =self.SCALE )
978           
979    def drag(self,x,y,event):
980        """
981        Hack function.  called when in select and left mouse goes down
982        """
983        pass
984   
985   
986    def drawEastingNorthingVertex(self,x,y,event):
987        """
988        draw a vertex object, plus add it to the mesh data structure
989
990        event isn't used
991        """
992        self.serial +=1
993        self.uniqueID = 'M*%d' % self.serial
994        #x_scaled =  self.SCALE*x
995        #y_scaled = -1*self.SCALE*y
996        #print "x y:", x,y
997        vert = self.Vertices.draw(x-self.mesh.geo_reference.get_xllcorner,
998                                  y-self.mesh.geo_reference.get_yllcorner,
999                                  self.mesh,
1000                                  self.uniqueID,
1001                                  self.SCALE,
1002                                  self.canvas,
1003                                  event) #FIXME why is event passed on.
1004        self.UserMeshChanged = True
1005        return vert
1006   
1007    def drawVertex(self,x,y,event):
1008        """
1009        draw a vertex object, plus add it to the mesh data structure
1010
1011        event isn't used
1012        """
1013        self.serial +=1
1014        self.uniqueID = 'M*%d' % self.serial
1015        #x_scaled =  self.SCALE*x
1016        #y_scaled = -1*self.SCALE*y
1017        #print "x y:", x,y
1018        vert = self.Vertices.draw(x,y,self.mesh,self.uniqueID,self.SCALE,self.canvas,event)
1019        self.UserMeshChanged = True
1020        return vert
1021     
1022    def drawHole(self,x,y,event):
1023        """
1024        draw a hole object, plus add it to the mesh data structure
1025
1026        event isn't used
1027        """
1028        self.serial +=1
1029        self.uniqueID = 'M*%d' % self.serial
1030        self.userMeshChanged = True
1031        hole = self.Holes.draw(x,y,self.mesh,self.uniqueID,self.SCALE,self.canvas,event)
1032        return hole   
1033   
1034    def drawRegion(self,x,y,event):
1035        """
1036        draw a region object, plus add it to the mesh data structure
1037
1038        event isn't used
1039        """
1040        self.serial +=1
1041        self.uniqueID = 'M*%d' % self.serial
1042        region = self.Regions.draw(x,y,self.mesh,self.uniqueID,self.SCALE,self.canvas,event)
1043        return region
1044   
1045    def selectSegmentPoint(self,x,y, event):
1046        """
1047        logic when selecting a vertex object to add a segment
1048        """
1049        found=False
1050        if event.widget.find_withtag(CURRENT): # if there's a widget with a tag
1051            [tag,string] = self.canvas.gettags(CURRENT) # get a list of them
1052            print "tag",tag  #tags ('M*1008', 'current')
1053            objectID = tag
1054            #print "Found!! objectID:", objectID
1055            if self.Vertices.hasKey(objectID): #isinstance(self.meshObjects[objectID],mesh.Vertex):
1056                vertex = self.Vertices.getMeshObject(objectID)
1057                found = True
1058                print "Found! vertex", vertex
1059           
1060        if found and self.selVertex == vertex:
1061            print "The selected vertex has already been selected"
1062            #The selected vertex has already been selected
1063            # therefore deselect it
1064            self.deselectVertex(self.selVertex, self.selVertexTag)
1065            found = False
1066                 
1067        if found: 
1068            #A vertex has been selected!
1069            if self.selVertex:
1070                if self.mesh.isUserSegmentNew(self.selVertex,vertex):
1071                    #vertex is the 2nd vertex
1072                    self.drawSegment(vertex,self.selVertex)
1073                    self.deselectVertex(self.selVertex, self.selVertexTag)
1074                    self.selectVertex(vertex,objectID)
1075            else:
1076                print "vertex is the 1st vertex" 
1077                #vertex is the 1st vertex
1078                self.selectVertex(vertex,objectID)
1079        else:
1080            print " There are no widgets.  This happen's too much"
1081                   
1082
1083    def selectVertex(self, vertex,objectID):
1084        """
1085        select a vertex object when adding a segment
1086        """
1087        self.canvas.delete(objectID)
1088        self.selVertex = vertex
1089        self.selVertexTag = objectID
1090        vertex.draw(self.canvas,objectID, scale =self.SCALE ,colour = VERT_SELECT_ADDING_SEG_COLOR)
1091   
1092    def deselectVertex(self, vertex,objectID):
1093        """
1094        deselect a vertex object when adding a segment
1095        """
1096        self.canvas.delete(objectID)
1097        self.selVertex = None
1098        self.selVertexTag = None
1099        vertex.draw(self.canvas,objectID,  scale =self.SCALE )
1100         
1101    def drawSegment(self,v1,v2):
1102        """
1103        Create a seg object, draw it and add it to the mesh data structure
1104        """
1105        self.serial +=1
1106        self.uniqueID = 'M*%d' % self.serial
1107        self.userMeshChanged = True
1108        seg = self.Segments.draw(v1,v2,self.mesh,self.uniqueID,self.SCALE,self.canvas,None)
1109        return seg
1110    def printGeoReference(self):
1111        try:
1112            print "geo reference", self.mesh.geo_reference
1113        except:
1114            print "no geo reference"
1115       
1116    def visualiseMesh(self,mesh):
1117        """
1118        visualise vertices, segments, triangulation, holes
1119        """
1120        if self.Visualise:
1121            for triangle in mesh.getTriangulation():
1122                self.serial +=1
1123                self.uniqueID = 'M*%d' % self.serial
1124                self.Triangles.visualise(triangle,
1125                                        self.uniqueID,
1126                                        self.canvas,
1127                                        self.SCALE)
1128
1129        if self.Visualise:
1130            Triangles = mesh.sets[mesh.setID[self.selSet]]
1131            for triangle in Triangles:
1132                triangle.draw(self.canvas,1,
1133                              scale = self.SCALE,
1134                              colour = SET_COLOUR)
1135
1136        for segment in mesh.getUserSegments():
1137            self.serial +=1
1138            self.uniqueID = 'M*%d' % self.serial
1139            self.Segments.visualise(segment,
1140                                    self.uniqueID,
1141                                    self.canvas,
1142                                    self.SCALE)
1143        for vertex in mesh.getUserVertices():
1144            self.serial +=1
1145            self.uniqueID = 'M*%d' % self.serial
1146            self.Vertices.visualise(vertex,
1147                                    self.uniqueID,
1148                                    self.canvas,
1149                                    self.SCALE)
1150           
1151        for hole in mesh.getHoles():
1152            self.serial +=1
1153            self.uniqueID = 'M*%d' % self.serial
1154            self.Holes.visualise(hole,
1155                                    self.uniqueID,
1156                                    self.canvas,
1157                                    self.SCALE)   
1158        for region in mesh.getRegions():
1159            self.serial +=1
1160            self.uniqueID = 'M*%d' % self.serial
1161            self.Regions.visualise(region,
1162                                    self.uniqueID,
1163                                    self.canvas,
1164                                    self.SCALE)
1165    def normalise4ObjMesh(self):
1166        if self.mesh:
1167            self.clearSelections()
1168            self.canvas.delete(ALL)
1169            self.mesh.normaliseMesh(400,-200,20)
1170            self.visualiseMesh(self.mesh)
1171            self.ResizeToFit()
1172            self.ResizeToFit()
1173           
1174    def normaliseMesh(self):
1175        if self.mesh:
1176            self.clearSelections()
1177            self.canvas.delete(ALL)
1178            self.mesh.normaliseMesh(1,0,1)
1179            self.visualiseMesh(self.mesh)
1180            self.ResizeToFit()
1181            self.ResizeToFit()
1182           
1183       
1184    def clearMesh(self):
1185        """Clear the current mesh object, and the canvas """
1186       
1187        self.clearSelections()
1188        self.canvas.delete(ALL)
1189        self.deleteMesh()
1190        self.initData()
1191        self.createMesh()
1192
1193    def exportObj(self):
1194        fileType = "obj"
1195        fileTypeDesc = "obj mesh"
1196       
1197        ofile = tkFileDialog.asksaveasfilename(filetypes=[(fileTypeDesc, fileType),
1198                                                ("All Files", "*")])
1199        if ofile:
1200            addOn = "." + fileType
1201            jumpback = - len(addOn)
1202            if ofile[jumpback:] != addOn: 
1203                ofile = ofile + addOn
1204            try:
1205                self.mesh.exportASCIIobj(ofile)
1206            except IOError:
1207                showerror('Export ASCII file',
1208                                   'Can not write to file.')
1209            except RuntimeError:
1210                showerror('Export ASCII file',
1211                                   'No triangulation to export.')
1212
1213   
1214
1215    def ImportUngenerate(self):
1216        ofile = tkFileDialog.askopenfilename(initialdir=self.currentPath,
1217                                             filetypes=[ ("ungenerated polygon information", "txt"),
1218                                           ("All Files", "*")])
1219        if ofile == "":
1220            # The user cancelled the loading action
1221            return
1222       
1223        try:
1224            self.clearSelections()
1225            self.canvas.delete(ALL)
1226            dict = mesh.importUngenerateFile(ofile)
1227            self.mesh.addVertsSegs(dict)
1228           
1229        except SyntaxError: 
1230            #this is assuming that the SyntaxError is thrown in
1231            #loadxyafile
1232            showerror('File error',
1233                      ofile + ' is not in the correct format.')
1234        except IOError: 
1235            #!!! this error type can not be thrown?
1236            showerror('File error',
1237                      'file ' + ofile + ' could not be found.')
1238        except RuntimeError: 
1239            showerror('File error',
1240                  'file ' + ofile + ' has an unknown file type.')
1241   
1242        self.visualiseMesh(self.mesh)
1243        self.ResizeToFit()
1244       
1245    def exportASCIIsegmentoutlinefile(self):
1246       
1247        ofile = tkFileDialog.asksaveasfilename(initialdir=self.currentPath,
1248                                               filetypes=[("mesh", "*.tsh *.msh"),
1249                                             ("All Files", "*")])
1250           
1251        if ofile:
1252            # .tsh is the default file format
1253            if (ofile[-4:] == ".tsh" or ofile[-4:] == ".msh"): 
1254                self.currentFilePathName = ofile
1255            else:
1256                self.currentFilePathName = ofile + ".tsh"
1257               
1258            try:
1259                self.mesh.exportASCIIsegmentoutlinefile(ofile)
1260            except IOError: #FIXME should this function be throwing any errors?
1261                showerror('Export ASCII file',
1262                                   'Can not write to file.')
1263
1264    def exportPointsFile(self):
1265        ofile = tkFileDialog.asksaveasfilename(initialdir=self.currentPath,
1266                                         filetypes=[("point files",
1267                                                     "*.xya *.pts"),
1268                                                ("All Files", "*")])
1269        if ofile:
1270            # .xya is the default file format
1271            if (ofile[-4:] == ".xya" or ofile[-4:] == ".pts"): 
1272                self.currentFilePathName = ofile
1273            else:
1274                self.currentFilePathName = ofile + ".xya"
1275               
1276            try:
1277                self.mesh.exportPointsFile(ofile)
1278            except IOError:
1279                showerror('Export ASCII file',
1280                                   'Can not write to file.')
1281                   
1282    def importFile(self):
1283        """
1284        import mesh data from a variety of formats (currently 2!)
1285        """
1286        print "self.currentPath",self.currentPath
1287        ofile = tkFileDialog.askopenfilename(initialdir=self.currentPath,
1288                                             filetypes=[ ("text Mesh", "*.tsh *.msh"),
1289                                                         ("points", "*.xya *.pts"),
1290                                           ("All Files", "*")])
1291        if ofile == "":
1292            # The user cancelled the loading action
1293            return
1294       
1295        try:
1296            newmesh = mesh.importMeshFromFile(ofile)
1297            self.currentPath, dummy = os.path.split(ofile)
1298            #print "be good self.currentPath",self.currentPath
1299            self.currentFilePathName = ofile
1300            self.clearMesh()
1301            self.mesh = newmesh
1302
1303            #FIXME - to speed things up, don't visualise the mesh
1304            # use ResizeToFitWrapper
1305            self.visualiseMesh(self.mesh)
1306            self.ResizeToFit()
1307       
1308        except IOError: 
1309            #!!! this error type can not be thrown?
1310            showerror('File error',
1311                      'file ' + ofile + ' could not be loaded.')
1312
1313        except RuntimeError: 
1314            showerror('File error',
1315                  'file ' + ofile + ' has an unknown file type.')
1316        # Could not get the file name to showup in the title
1317        #appname =  ofile + " - " + APPLICATION_NAME
1318        #print "appname",appname
1319       
1320        except load_mesh.loadASCII.TitleAmountError: 
1321            showerror('File error',
1322                  'file ' + ofile + ' has a bad title line (first line).')
1323
1324   
1325    def ResizeToFitWrapper(self, Parent):
1326        """
1327        The parent attribute isn't used by this function.
1328        need to understand toolbarbutton.py to know how to
1329        get rid of it.
1330        """
1331        self.ResizeToFit()
1332       
1333    def ResizeToFit(self):
1334        """Visualise the mesh so it fits in the window"""
1335        if self.mesh.getUserVertices() == []:
1336            return #There are no vertices!
1337        # Resize the window
1338        self.scrolledcanvas.resizescrollregion()
1339        # I need this so the xview values are correct
1340        self.scrolledcanvas.update()
1341       
1342        xtop, xbottom = self.scrolledcanvas.xview()
1343        ytop, ybottom = self.scrolledcanvas.yview()
1344        xdiff = xbottom-xtop
1345        ydiff = ybottom-ytop
1346        if xdiff == 1 and xdiff == 1:
1347            #The mesh might be too small.
1348            #Make it too large, then resize
1349            #!!! Recursive hack.  Should be a better way
1350            fraction = 50
1351            self.SCALE *= fraction
1352            self.scrolledcanvas.scale(ALL, 0, 0, fraction, fraction)
1353            self.ResizeToFit()
1354        else:
1355            # without 0.99 some of the mesh may be off screen
1356            fraction = 0.99*min(xdiff,ydiff) 
1357            self.selectZoom(fraction)
1358           
1359    def saveDrawing(self):
1360        """
1361        Save the current drawing
1362        """
1363        #print "dsg!!! self.currentFilePathName ",self.currentFilePathName
1364        if (self.currentFilePathName[-4:] != ".tsh" or
1365            self.currentFilePathName[-4:] != ".msh"):
1366            # force user to choose a name
1367            self.saveAsDrawing()
1368        else:
1369            self.exportASCIItriangulationfile(self.currentFilePathName)
1370
1371    def saveAsDrawing(self):
1372        """
1373        Save the current drawing, prompting for a file name
1374        """
1375        ofile = tkFileDialog.asksaveasfilename(initialdir=self.currentPath,
1376                                               filetypes=[("mesh", "*.tsh *.msh"),
1377                                             ("All Files", "*")])
1378           
1379        if ofile:
1380            # .tsh is the default file format
1381            if (ofile[-4:] == ".tsh" or ofile[-4:] == ".msh"): 
1382                self.currentFilePathName = ofile
1383            else:
1384                self.currentFilePathName = ofile + ".tsh"
1385            self.exportASCIItriangulationfile(self.currentFilePathName)
1386
1387    def exportASCIItriangulationfile(self,currentFilePathName):
1388        """
1389        Have a warning prompt when saving a mesh where the generated mesh is
1390        different from the user mesh - eg boundary tags that aren't carried
1391        thru. Warning ~"Mesh not generated after changes.  Generate mesh?  "
1392        - cancel, don't gen, don't save.  Yes - generate mesh, go to save
1393        screen.  No - goto save screen.  To implement this need to know when
1394        the user has done a change, and the mesh hasn't been generated.  If
1395        there is no generated mesh do not prompt.
1396        """
1397        #print "self.UserMeshChanged",self.UserMeshChanged
1398        #print "self.mesh.isTriangulation()",self.mesh.isTriangulation()
1399        if (self.UserMeshChanged) and self.mesh.isTriangulation():
1400           
1401            m = _show("Warning",
1402                                   "A triangulation has not been generated, after mesh changes.  Generate triangulation before saving?",
1403                                   icon=QUESTION, 
1404                                   type=YESNOCANCEL)
1405            if m == "no":
1406                self.mesh.export_mesh_file(currentFilePathName)
1407                self.UserMeshChanged = False
1408            elif m == "cancel":
1409                pass
1410            elif m == "yes":
1411                self.windowMeshGen(None)
1412                self.mesh.export_mesh_file(currentFilePathName)
1413        else:
1414            self.mesh.export_mesh_file(currentFilePathName)
1415            self.UserMeshChanged = False
1416           
1417    def initData(self):
1418        """
1419        Initialise various lists and flags
1420        """
1421        self.serial      = 1000
1422        self.currentFilePathName = 'untitled'
1423
1424        # these are attributes I've added
1425        self.SCALE       = 1
1426        self.selVertex   = None     #The last vertex selected, in draw seg mode
1427        self.selVertexTag   = None     # The selected vertex drawn object tag
1428        self.mesh        = None
1429        self.MeshMinAngle = 20
1430        self.MeshMaxArea = 200
1431        self.MeshnumTriangles = 20
1432        self.MeshMaxAreaLast = False
1433        self.selMeshObject = None  # The mesh object selected in the current mode
1434        self.selMeshTag = None
1435        mesh.Segment.set_default_tag("")
1436        self.UserMeshChanged = False
1437        self.meshLastAlpha = None
1438       
1439        self.Visualise = True #Is the mesh shown or not?
1440   
1441    def ipostscript(self):
1442        """
1443        Print the canvas as a postscript file
1444        """
1445        ofile = tkFileDialog.asksaveasfilename(initialdir=self.currentPath,
1446                                               filetypes=[("postscript", "ps"),
1447                                                          ("All Files", "*")]) 
1448        if ofile:
1449            if ofile[-3:] != ".ps": 
1450                ofile = ofile + ".ps"
1451            postscript = self.canvas.postscript()
1452            fd = open(ofile, 'w')
1453            fd.write(postscript)
1454            fd.close()
1455       
1456    def close(self):
1457        self.quit()
1458       
1459    def createInterface(self):
1460        """
1461        Call all functions that create the GUI interface
1462        """
1463        self.initData()
1464        self.createMesh()
1465        AppShell.AppShell.createInterface(self)
1466        self.createButtons()
1467        self.createMenus()
1468        self.createBase()
1469        self.createTools()
1470        self.createZooms()
1471        self.createEdits()
1472        self.createSetTools()
1473        self.createSetIcons()
1474        self.createVisualiseIcons()
1475        #self.addVertsAndSegs() # !!!DSG start pmesh with a triangle
1476        self.selectFunc('pointer')
1477        self.currentPath = os.getcwd() 
1478
1479    def loadtestmesh(self,ofile):
1480        """
1481        debugging script to test loading a file
1482        """
1483        fd = open(ofile)
1484        a = mesh.Vertex (-10.0, 0.0)
1485        d = mesh.Vertex (0.0, 4.0)
1486        f = mesh.Vertex (4.0,0.0)
1487        g = mesh.Vertex (-5.0,5.0)
1488       
1489        s1 = mesh.Segment(a,d)
1490        s2 = mesh.Segment(d,f)
1491        s3 = mesh.Segment(a,f)
1492
1493        r1 = mesh.Region(0.3, 0.3)
1494       
1495        m = mesh.Mesh(userVertices=[a,d,f,g], userSegments=[s1,s2,s3], regions=[r1] )
1496       
1497        fd.close()
1498        print 'returning m'
1499        return oadtestmesh(ofile)
1500         
1501class  AddVertexDialog(Dialog):
1502    """
1503    Dialog box for adding a vertex by entering co-ordindates
1504    """
1505    def body(self, master):
1506        """
1507        GUI description
1508        """
1509        self.title("Add New Vertex")
1510       
1511        Label(master, text='X position:').grid(row=0, sticky=W)
1512        Label(master, text='Y position:').grid(row=1, sticky=W)
1513
1514        self.xstr   = Entry(master, width = 16, name ="entry")
1515        self.ystr  = Entry(master, width = 16)
1516       
1517        self.xstr.grid(row=0, column=1, sticky=W)
1518        self.ystr.grid(row=1, column=1, sticky=W)
1519        self.xstr.focus_force()
1520        self.= 0
1521        self.= 0
1522        self.xyValuesOk = False
1523 
1524
1525    def apply(self):
1526        """
1527        check entered values
1528        """
1529        try:
1530            self.x = float(self.xstr.get())
1531            self.y = float(self.ystr.get())
1532            self.xyValuesOk = True
1533           
1534        except ValueError:
1535            showerror('Bad Vertex values',
1536                                   'X Y values are not numbers.')
1537       
1538
1539class  AutoSegmentDialog(Dialog):
1540    """
1541    Dialog box for adding segments
1542    """
1543    def __init__(self, parent, alpha):
1544        self.alpha = alpha
1545        Dialog.__init__(self, parent)
1546       
1547    def body(self, master):
1548        """
1549        GUI description
1550        """
1551        self.title("Automatically Add Segments")
1552
1553        self.use_optimum = IntVar()
1554        self.use_optimum.set(AUTO) # should initialise the radio buttons.
1555                                   #  It doesn't
1556                                   
1557        #self.use_optimum.set(NO_SELECTION)
1558        self.ck = Radiobutton(master, value = AUTO, variable=self.use_optimum) 
1559        self.ck.grid(row=1, column=0)
1560        Label(master, text='Use optimum alpha').grid(row=1, column=1, sticky=W)
1561
1562        self.ck2 = Radiobutton(master, value = SET_ALPHA,
1563                               variable=self.use_optimum) 
1564        self.ck2.grid(row=2, column=0)
1565       
1566        Label(master, text='alpha:').grid(row=2, column=1, sticky=W)
1567        if (self.alpha):
1568            alphaVar = StringVar()
1569            alphaVar.set(self.alpha)
1570            self.alpha_str  = Entry(master,
1571                                     textvariable = alphaVar,
1572                                     width = 16, name ="entry") 
1573        else: 
1574            self.alpha_str = Entry(master, width = 16, name ="entry")
1575       
1576        self.alpha_str.grid(row=2, column=3, sticky=W)
1577
1578        #boundary type buttons
1579        self.raw_boundary = IntVar()
1580        self.remove_holes = IntVar()
1581        self.smooth_indents = IntVar()
1582        self.expand_pinch = IntVar()
1583        self.ck3 = Checkbutton(master, state=NORMAL,
1584                               variable=self.raw_boundary) 
1585        self.ck3.grid(row=3, column=0)
1586        Label(master, text='Raw boundary').grid(row=3, column=1, sticky=W)
1587        #
1588        self.ck4 = Checkbutton(master, state=NORMAL,
1589                               variable=self.remove_holes) 
1590        self.ck4.grid(row=4, column=0)
1591        Label(master, text='Remove small holes').grid(row=4,column=1, sticky=W)
1592        #
1593        self.ck5 = Checkbutton(master,state=NORMAL,
1594                               variable=self.smooth_indents) 
1595        self.ck5.grid(row=5, column=0)
1596        Label(master,
1597              text='Remove sharp indents').grid(row=5, column=1, sticky=W)
1598        #
1599        self.ck6 = Checkbutton(master,state=NORMAL,
1600                               variable=self.expand_pinch) 
1601        self.ck6.grid(row=6, column=0)
1602        Label(master,
1603              text='Remove pinch off').grid(row=6, column=1,  sticky=W)
1604
1605       
1606        self.alpha  = 0
1607        self.alphaValueOk = False
1608       
1609
1610    def apply(self):
1611        """
1612        check entered values
1613        """
1614        try:
1615            self.alpha = float(self.alpha_str.get())
1616            self.alphaValueOk = True
1617           
1618        except ValueError:
1619            pass
1620            #showerror('Bad Alpha value',
1621            #                       'Alpha is negative.')
1622
1623
1624class  AutoSegmentFilterDialog(Dialog):
1625    """
1626    Dialog box for adding segments
1627    """
1628    def __init__(self, parent):
1629        Dialog.__init__(self, parent)
1630       
1631    def body(self, master):
1632        """
1633        GUI description
1634        """
1635        self.title("Automatically Add Segments")
1636
1637        self.use_optimum = IntVar()
1638        self.use_optimum.set(AUTO) # should initialise the radio buttons.
1639                                   #  It doesn't
1640        self.boundary_type = IntVar()
1641                     
1642        #boundary type buttons
1643        self.raw_boundary = IntVar()
1644        self.remove_holes = IntVar()
1645        self.smooth_indents = IntVar()
1646        self.expand_pinch = IntVar()
1647       
1648        self.ck3 = Checkbutton(master, state=NORMAL,
1649                               variable=self.raw_boundary) 
1650        self.ck3.grid(row=3, column=0)
1651        Label(master, text='Raw boundary').grid(row=3, column=1, sticky=W)
1652        #
1653        self.ck4 = Checkbutton(master, state=NORMAL,
1654                               variable=self.remove_holes) 
1655        self.ck4.grid(row=4, column=0)
1656        Label(master, text='Remove small holes').grid(row=4,column=1, sticky=W)
1657        #
1658        self.ck5 = Checkbutton(master,state=NORMAL,
1659                               variable=self.smooth_indents) 
1660        self.ck5.grid(row=5, column=0)
1661        Label(master,
1662              text='Remove sharp indents').grid(row=5, column=1, sticky=W)
1663        #
1664        self.ck6 = Checkbutton(master,state=NORMAL,
1665                               variable=self.expand_pinch) 
1666        self.ck6.grid(row=6, column=0)
1667        Label(master,
1668              text='Remove pinch off').grid(row=6, column=1,  sticky=W)
1669       
1670       
1671
1672
1673class  MeshGenDialog(Dialog):
1674    """
1675    Dialog box for generating a mesh
1676    """
1677    # initial values, hard coded.
1678    # should be values associated with the current mesh
1679    lastMinAngle = 20
1680    lastMaxArea  = 100
1681
1682
1683    def __init__(self,
1684                 parent,
1685                 minAngle,
1686                 maxArea,
1687                 numTriangles,
1688                 MeshMaxAreaLast):
1689        self.minAngle = minAngle
1690        self.maxArea = maxArea
1691        self.numTriangles = numTriangles
1692        self.MeshMaxAreaLast = MeshMaxAreaLast
1693
1694        Dialog.__init__(self, parent)
1695
1696       
1697    def body(self, master):
1698        """
1699        GUI description
1700        """
1701        self.title("Generate Mesh")
1702       
1703        Label(master,
1704              text='Minimum Angle(0 - 40):').grid(row=0, sticky=W)
1705        Label(master,
1706              text='Angles>33 may not converge').grid(row=1, sticky=W)
1707        Label(master, text='Maximum Area:').grid(row=2, sticky=W)
1708        Label(master, text='OR # of triangles:').grid(row=3, sticky=W)
1709
1710
1711        minAngleVar = StringVar()
1712        minAngleVar.set(self.minAngle)
1713        self.minAnglestr   = Entry(master,
1714                                   width = 16,
1715                                   textvariable = minAngleVar,
1716                                   takefocus=1)
1717        if (self.MeshMaxAreaLast):
1718            maxAreaVar = StringVar()
1719            maxAreaVar.set(self.maxArea)
1720            self.maxAreastr  = Entry(master,
1721                                     textvariable = maxAreaVar,
1722                                     width = 16)   
1723            self.numTrianglesstr  = Entry(master,
1724                                          width = 16) 
1725        else: 
1726            self.maxAreastr  = Entry(master,
1727                                     width = 16)
1728            self.maxAreastr.focus_force()
1729            numTrianglesVar = StringVar()
1730            numTrianglesVar.set(self.numTriangles)   
1731            self.numTrianglesstr  = Entry(master,
1732                                          textvariable = numTrianglesVar,
1733                                          width = 16) 
1734
1735
1736        self.minAnglestr.grid(row=0, column=1, sticky=W)
1737        self.maxAreastr.grid(row=2, column=1, sticky=W)
1738        self.numTrianglesstr.grid(row=3, column=1, sticky=W)
1739
1740        self.numTriangles = 0
1741        self.minAngle  = 0
1742        self.maxArea  = 0
1743        self.ValuesOk = False
1744
1745
1746    def apply(self):
1747        """
1748        check entered values
1749        """
1750        self.goodMaxArea = self.goodNumTriangles = True
1751        self.ValuesOk = True
1752        try:
1753            self.minAngle = float(self.minAnglestr.get())
1754            MeshGenDialog.lastMinAngle =self.minAngle
1755        except ValueError:
1756            self.ValuesOk = False
1757            showerror('Bad mesh generation values',
1758                                   ' Values are not numbers.')
1759       
1760        try:   
1761            self.maxArea = float(self.maxAreastr.get())
1762            MeshGenDialog.lastMaxArea =self.maxArea
1763        except ValueError:
1764            self.goodMaxArea = False
1765         
1766        try:   
1767            self.numTriangles = int(self.numTrianglesstr.get())
1768            MeshGenDialog.lastNumTriangles =self.numTriangles
1769        except ValueError:
1770            self.goodNumTriangles= False
1771
1772        if self.goodMaxArea == False and self.goodNumTriangles == False:
1773            self.ValuesOk = False
1774            showerror('Bad mesh generation values',
1775                      'Values are not numbers.')
1776
1777        if self.goodMaxArea == True and self.goodNumTriangles == True:
1778            self.ValuesOk = False
1779            showerror('Bad mesh generation values',
1780                      'Give a maximum area OR number of triangles, not both.')
1781
1782        try: 
1783            # value checking
1784            if self.minAngle <0.0 or self.minAngle >40.0:
1785                raise IOError
1786            if self.goodMaxArea == True and self.maxArea <0.0:
1787                raise IOError
1788            if self.goodNumTriangles == True and self.numTriangles <=0:
1789                raise IOError
1790           
1791        except IOError:
1792            self.ValuesOk = False
1793            showerror('Bad mesh generation values',
1794                                   'Values are out of range.')
1795class  GeneralThresholdDialog(Dialog):
1796    """
1797    Dialog box for thresholding a set by entering minimum
1798    and maximum values
1799    """
1800    def __init__(self,
1801                 parent,
1802                 attribute_titles,
1803                 function_description):
1804        self.attribute_titles=attribute_titles
1805        self.function_description=function_description
1806
1807        Dialog.__init__(self, parent)
1808
1809
1810    def body(self, master):
1811        """
1812        GUI description
1813        """
1814        self.title("Threshold selected set")
1815        blurb1 = 'Threshold selected set between minimum'
1816        blurb2 = 'and maximum ' + self.function_description
1817
1818        Label(master,text=blurb1).grid(row=0, sticky=W)
1819        Label(master,text=blurb2).grid(row=1, sticky=W)
1820
1821        Label(master, text='minimum attribute:').grid(row=2, sticky=W)
1822        Label(master, text='maximum attribute:').grid(row=3, sticky=W)
1823        Label(master, text='attribute name').grid(row=4, sticky=W)
1824
1825
1826        nameVar = StringVar()
1827        nameVar.set('elevation')
1828
1829        self.minstr = Entry(master, width = 16, name ="entry")
1830        self.maxstr = Entry(master, width = 16)
1831        self.attstr = Entry(master, width = 16,textvariable = nameVar)
1832       
1833        self.minstr.grid(row=2, column=1, sticky=W)
1834        self.maxstr.grid(row=3, column=1, sticky=W)
1835        self.attstr.grid(row=4, column=1, sticky=W)
1836        self.minstr.focus_force()
1837        self.min  = 0
1838        self.max  = 0
1839        self.attribute_name = 'elevation'
1840        self.minmaxValuesOk = False
1841       
1842    def apply(self):
1843        self.minmaxValuesOk = True
1844        try:
1845            self.min = float(self.minstr.get())
1846            self.max = float(self.maxstr.get())
1847        except ValueError:
1848            self.minmaxValuesOk = False
1849            showerror('Bad mesh generation values',
1850                                   ' Values are not numbers.')
1851        try:
1852            self.attribute_titles.index(self.attstr.get())#dodgey.
1853            self.attribute_name = self.attstr.get()
1854        except ValueError:
1855            self.attribute_name = None
1856            showerror('Bad attribute name',
1857                                   'Using h = 1')
1858
1859class  ThresholdDialog(Dialog):
1860    """
1861    Dialog box for thresholding a set by entering minimum
1862    and maximum values
1863    """
1864    def __init__(self,
1865                 parent,
1866                 attribute_titles):
1867        self.attribute_titles=attribute_titles
1868        Dialog.__init__(self, parent)
1869
1870
1871    def body(self, master):
1872        """
1873        GUI description
1874        """
1875        self.title("Threshold selected set")
1876       
1877        Label(master, text='minimum attribute:').grid(row=0, sticky=W)
1878        Label(master, text='maximum attribute:').grid(row=1, sticky=W)
1879        Label(master, text='attribute name').grid(row=2, sticky=W)
1880
1881
1882        nameVar = StringVar()
1883        nameVar.set('elevation')
1884
1885        self.minstr   = Entry(master, width = 16, name ="entry")
1886        self.maxstr   = Entry(master, width = 16)
1887        self.attstr   = Entry(master, width = 16,textvariable = nameVar)
1888       
1889        self.minstr.grid(row=0, column=1, sticky=W)
1890        self.maxstr.grid(row=1, column=1, sticky=W)
1891        self.attstr.grid(row=2, column=1, sticky=W)
1892        self.minstr.focus_force()
1893        self.min  = 0
1894        self.max  = 0
1895        self.attribute_name = 'elevation'
1896        self.minmaxValuesOk = False
1897       
1898    def apply(self):
1899        self.minmaxValuesOk = True
1900        try:
1901            self.min = float(self.minstr.get())
1902            self.max = float(self.maxstr.get())
1903        except ValueError:
1904            self.minmaxValuesOk = False
1905            showerror('Bad mesh generation values',
1906                                   ' Values are not numbers.')
1907        try:
1908            self.attribute_titles.index(self.attstr.get())#dodgey.
1909            self.attribute_name = self.attstr.get()
1910        except ValueError:
1911            self.minmaxValuesOk = False
1912            showerror('Bad attribute name',
1913                                   ' Attribute not in mesh.')
1914
1915
1916class  Courant_ThresholdDialog(Dialog):
1917    """
1918    Dialog box for thresholding a set by entering minimum
1919    and maximum values
1920    """
1921    def __init__(self,
1922                 parent,
1923                 attribute_titles):
1924        self.attribute_titles=attribute_titles
1925        Dialog.__init__(self, parent)
1926
1927
1928    def body(self, master):
1929        """
1930        GUI description
1931        """
1932        self.title("Courant_Threshold selected set")
1933       
1934        Label(master, text='minimum attribute:').grid(row=0, sticky=W)
1935        Label(master, text='maximum attribute:').grid(row=1, sticky=W)
1936        Label(master, text='attribute name').grid(row=2, sticky=W)
1937
1938
1939        nameVar = StringVar()
1940        nameVar.set('elevation')
1941
1942        self.minstr   = Entry(master, width = 16, name ="entry")
1943        self.maxstr   = Entry(master, width = 16)
1944        self.attstr   = Entry(master, width = 16,textvariable = nameVar)
1945       
1946        self.minstr.grid(row=0, column=1, sticky=W)
1947        self.maxstr.grid(row=1, column=1, sticky=W)
1948        self.attstr.grid(row=2, column=1, sticky=W)
1949        self.minstr.focus_force()
1950        self.min  = 0
1951        self.max  = 0
1952        self.attribute_name = 'elevation'
1953        self.minmaxValuesOk = False
1954       
1955    def apply(self):
1956        self.minmaxValuesOk = True
1957        try:
1958            self.min = float(self.minstr.get())
1959            self.max = float(self.maxstr.get())
1960        except ValueError:
1961            self.minmaxValuesOk = False
1962            showerror('Bad mesh generation values',
1963                                   ' Values are not numbers.')
1964        try:
1965            self.attribute_titles.index(self.attstr.get())#dodgey.
1966            self.attribute_name = self.attstr.get()
1967        except ValueError:
1968            self.minmaxValuesOk = False
1969            showerror('Bad attribute name',
1970                                   ' Attribute not in mesh.')
1971
1972
1973class SmoothDialog(Dialog):
1974    """
1975    Dialog box for setting the number of triangles
1976    used to make up dilation or erosion
1977    """
1978    def body(self, master):
1979        """
1980        GUI description
1981        """
1982        self.title("Enter the minimum radius to remove")
1983       
1984        Label(master, text='radius:').grid(row=0, sticky=W)
1985
1986        self.min_radius = Entry(master, width = 16, name ="entry")
1987       
1988        self.min_radius.grid(row=0, column=1, sticky=W)
1989        self.min_radius.focus_force()
1990        self.min = 2.
1991        self.valueOK = False
1992       
1993    def apply(self):
1994        self.valueOK = True
1995        try:
1996            self.min = float(self.min_radius.get())
1997            self.min_radius = self.min
1998        except ValueError:
1999            self.valueOK = False
2000            showerror('Bad Number',
2001                                   ' Value not a number')
2002
2003class  setStructureNumberDialog(Dialog):
2004    """
2005    Dialog box for setting the number of triangles
2006    used to make up dilation or erosion
2007    """
2008    def body(self, master):
2009        """
2010        GUI description
2011        """
2012        self.title("Set number of elements effected by morphing sets")
2013       
2014        Label(master, text='number:').grid(row=0, sticky=W)
2015
2016        self.number = Entry(master, width = 16, name ="entry")
2017       
2018        self.number.grid(row=0, column=1, sticky=W)
2019        self.number.focus_force()
2020        self.number = 0
2021        self.numberOk = False
2022       
2023    def apply(self):
2024        self.numberOk = True
2025        try:
2026            self.number = int(self.number.get())
2027        except ValueError:
2028            self.numberOK = False
2029            showerror('Bad mesh generation values',
2030                                   ' Values are not numbers.')
2031
2032
2033     
2034if __name__ == '__main__':
2035    draw = Draw()
2036    draw.run()
2037    #profile.run('draw.run()', 'pmeshprof')   
2038
Note: See TracBrowser for help on using the repository browser.