source: inundation/pmesh/graphical_mesh_generator.py @ 3492

Last change on this file since 3492 was 3492, checked in by duncan, 18 years ago

Cleaning things up

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