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

Last change on this file since 1106 was 1033, checked in by duncan, 20 years ago

added new function, not used or tested

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