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

Last change on this file since 1159 was 1159, checked in by prow, 20 years ago

tri2polyset - weeding duplicate verities

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