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

Last change on this file since 614 was 410, checked in by duncan, 20 years ago

cleaning up

File size: 46.8 KB
Line 
1import  Pmw, AppShell, math, time, string, marshal
2from toolbarbutton import ToolBarButton
3import tkFileDialog
4from   tkSimpleDialog import Dialog
5import mesh
6from Tkinter import  FALSE,TRUE, Frame,X, LEFT,YES,BOTH,ALL,Widget,CURRENT, Label,W, Entry, E, StringVar, END
7#from cursornames import TLC,TRC, BLC, BRC, TS, RS, LS, BS
8from tkMessageBox import showerror, _show, QUESTION,YESNOCANCEL
9import types
10import visualmesh
11import os
12
13# CONSTANTS
14VERT_SELECT_ADDING_SEG_COLOR = 'orange'
15SELECT_COLOR = 'red'
16SEG_COLOUR = 'blue'
17TRIANGLE_COLOUR = 'green'
18APPLICATION_NAME = 'Pmesh'
19
20class Draw(AppShell.AppShell):
21    usecommandarea = 1
22    appname        = APPLICATION_NAME
23    frameWidth     = 840
24    frameHeight    = 600
25   
26   
27    def createButtons(self):
28        """
29        Add buttons to the bottom of the GUI
30        """
31        self.buttonAdd('Postscript',
32              helpMessage='Save current drawing (as PostScript)',
33              statusMessage='',
34              command=self.ipostscript)
35        self.buttonAdd('Clear', helpMessage='Delete the mesh',
36              statusMessage='', command=self.clearMesh)
37        self.buttonAdd('Close', helpMessage='Close Screen',
38              statusMessage='', command=self.close)
39       
40    def createBase(self):
41        """
42        Create the GUI framework.  Set up the GUI
43        """
44        self.toolbar = self.createcomponent('toolbar', (), None,
45                  Frame, (self.interior(),), background="gray90")
46        self.toolbar.pack(fill=X)
47
48        self.scrolledcanvas =  self.createcomponent('ScrolledCanvas', (), None,
49                                       Pmw.ScrolledCanvas, (self.interior(),)
50                                       ,borderframe = 1
51                                       ,labelpos = 'n'
52                                       )
53        self.scrolledcanvas.configure(hscrollmode = 'dynamic')
54        self.scrolledcanvas.configure(vscrollmode = 'dynamic')
55        self.scrolledcanvas.pack(side=LEFT, expand=YES, fill=BOTH)
56        self.canvas = self.scrolledcanvas.component('canvas')
57        self.canvas.configure( background="white" )
58       
59        self.canvas.pack(side=LEFT, expand=YES, fill=BOTH)
60
61        Widget.bind(self.canvas, "<Button-1>", self.mouseDown)
62        Widget.bind(self.canvas, "<Button3-ButtonRelease>", self.rightMouseUp)
63        Widget.bind(self.canvas, "<Button2-ButtonRelease>",self.DeleteSelectedMeshObject)
64        # "<Delete>" didn't work..
65        #Widget.bind(self.canvas, "<Delete>", self.DeleteSelectedMeshObject)
66
67        #self.root.bind("<KeyPress>", self.setRegular)
68        #self.root.bind("<KeyRelease>", self.setRegular)
69       
70        self.scrolledcanvas.resizescrollregion()
71
72#     def setRegular(self, event):
73#         if event.type == '2' and event.keysym == 'Shift_L':
74#             self.regular = TRUE
75#         else:
76#             self.regular = FALSE
77
78    def createMenus(self):
79        """
80        Add menus to the top of the GUI
81        """
82        self.menuBar.deletemenuitems('File',0)
83        self.menuBar.addmenuitem('File', 'command', 'New mesh',
84                                 label='New', command=self.clearMesh)
85        self.menuBar.addmenuitem('File', 'command', 'Open mesh',
86                                 label='Open...', command=self.importFile)
87        self.menuBar.addmenuitem('File', 'command', 'Save mesh',
88                                 label='Save', command=self.saveDrawing)
89        self.menuBar.addmenuitem('File', 'command', 'Save mesh',
90                                 label='SaveAs...', command=self.saveAsDrawing)
91       
92        self.menuBar.addmenuitem('File', 'separator')
93        self.menuBar.addmenuitem('File', 'command',
94                                 'Add ungenerated file from arcGIS',
95                                 label='Add ungenerated file...',
96                                 command=self.ImportUngenerate)
97       
98        self.menuBar.addmenuitem('File', 'command',
99                                 'Export ASCII obj',
100                                 label='Export ASCII obj',
101                                 command=self.exportObj)
102       
103        self.menuBar.addmenuitem('File', 'command',
104                                 'Export ASCII segment outline',
105                                 label='Export ASCII segment outline...',
106                                 command=self.exportASCIIsegmentoutlinefile)
107       
108        self.menuBar.addmenuitem('File', 'command',
109                                 'Export ASCII xya file',
110                                 label='Export ASCII xya file...',
111                                 command=self.exportxyafile)
112       
113        self.menuBar.addmenuitem('File', 'command',
114                                 'add Segments to connect all vertices'  ,
115                                 label='join vertices',
116                                 command=self.joinVertices)
117        self.menuBar.addmenuitem('File', 'command',
118                                 'add Segments to form alpha shape'  ,
119                                 label='Auto segment',
120                                 command=self.autoSegment)
121        self.menuBar.addmenuitem('File', 'command', 'Normalise mesh',
122                                 label='Normalise mesh', command=self.normaliseMesh)
123        self.menuBar.addmenuitem('File', 'command', 'Normalise mesh for glutobj',
124                                 label='Normalise mesh for glutobj', command=self.normalise4ObjMesh)
125        self.menuBar.addmenuitem('File', 'separator')
126        self.menuBar.addmenuitem('File', 'command', 'Exit program',
127                                 label='Exit', command=self.quit)
128
129    def createTools(self):
130        """
131        Add buttons to the top of the GUI
132        """
133        self.mouseDownFunc = {}
134        self.modeClass = {}
135        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif',
136                      width=10, state='disabled')
137        for key, balloon, mouseDownFunc, Mode in [
138            ('pointer','Edit drawing eventually.  Right now this does nothing', self.drag, None)
139            ,('vertex',    'Vertex mode', self.drawVertex, mesh.Vertex)
140            ,('segment', 'Segment mode',self.selectSegmentPoint, mesh.Segment)
141            ,('hole', 'hole mode',self.drawHole, mesh.Hole)
142            ,('region', 'region mode',self.drawRegion, mesh.Region)
143            ]:
144            t = ToolBarButton(self, self.toolbar, key, '%s.gif' % key,
145                          command=self.selectFunc, balloonhelp=balloon,
146                               statushelp='')
147            t.cycle("DrawMode")
148            if key == 'pointer': #FIXME- this is specified in line 1062 as well
149                                 # self.selectFunc('pointer')
150                self.curFunc  = self.drawVertex
151                t.setInitialSunkenButton("DrawMode")
152            self.modeClass[key] = Mode
153            # for actions that occur when the mouse goes down
154            self.mouseDownFunc[key] = mouseDownFunc
155         
156    def createZooms(self):
157        """
158        Add zoom buttons to the top of the GUI
159        """
160        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif', width=10,
161                      state='disabled')
162        zoom = '0.5'
163        ToolBarButton(self, self.toolbar, zoom, 'zoom%s.gif' %
164                      zoom, command=self.selectZoom,
165                      balloonhelp='*%s zoom' % zoom,
166                      statushelp='')
167           
168        ToolBarButton(self, self.toolbar,'1.0', 'zoomToMesh.gif',
169                      command=self.ResizeToFitWrapper,
170                      balloonhelp='Zooms to mesh size',
171                      statushelp='')
172        zoom = '2'
173        ToolBarButton(self, self.toolbar, zoom, 'zoom%s.gif' %
174                      zoom, command=self.selectZoom,
175                      balloonhelp='*%s zoom' % zoom,
176                      statushelp='')
177
178    def createEdits(self):
179        """
180        Add Edit buttons to the top of the GUI
181        """
182        ToolBarButton(self, self.toolbar, 'sep', 'sep.gif', width=10,
183                      state='disabled')
184        for key, func, balloon in [
185                ('addVertex', self.windowAddVertex, 'add Vertex'),
186                ('edit', self.windowEdit, 'edit selected object'),
187                ('default', self.windowDefault, 'set default value for selected mode'),
188                ('joinVer', self.joinVerticesButton, 'add Segments to connect all vertices'),     
189                ('autoSeg', self.autoSegmentButton, 'add Segments to form alpha shape'),
190                ('meshGen', self.windowMeshGen, 'Generate Mesh')]:
191            ToolBarButton(self, self.toolbar, key, '%s.gif' % key,
192                          command=func, balloonhelp=balloon,
193                               statushelp='' )
194
195    def createMesh(self):
196        """
197        Build the data structures for storing the mesh objects
198        """
199        self.mesh = mesh.Mesh()
200       
201        self.Vertices = visualmesh.vPoints(mesh.Vertex)
202        self.Segments = visualmesh.vSegments(mesh.Segment)
203        self.Holes = visualmesh.vPoints(mesh.Hole)
204        self.Regions = visualmesh.vRegions(mesh.Region)
205        self.UserMesh = visualmesh.vMesh([self.Vertices,self.Segments,self.Holes,self.Regions])
206       
207        self.Triangles = visualmesh.vTriangles(mesh.Triangle)
208
209
210    def deleteMesh(self):
211        """
212        Delete the data structures for storing the mesh objects
213        """
214        self.mesh = None
215        self.Vertices = None
216        self.Segments = None
217        self.Triangles = None
218       
219    def addVertsAndSegs(self):
220        """
221        Automatically add some verts and segs to the mesh.Used in Debugging
222        """
223        v1 = self.drawVertex(0,0,None)
224        v2 = self.drawVertex(0,200,None)
225        v3 = self.drawVertex(200,0,None)
226        v3 = self.drawVertex(300,100,None)
227        self.drawSegment(v1,v2)
228        self.drawSegment(v1,v3)
229        self.drawSegment(v2,v3)
230        #Since the new vertex may be off screen
231        self.scrolledcanvas.resizescrollregion()
232       
233    def selectFunc(self, tag):
234        """
235        Change the current mode class
236        When changing from one mode to another
237        """
238        self.mouseDownCurFunc = self.mouseDownFunc[tag]
239        self.curModeClass = self.modeClass[tag]
240        self.clearSelections()
241        self.canvas.config(cursor='arrow')
242#        I can make it arrow, but it will change back to pointer, after
243#        adding an object
244#        if self.curFunc == self.func['pointer']:
245#            self.canvas.config(cursor='arrow')
246#         else:
247#             self.canvas.config(cursor='crosshair')
248
249    def clearSelections(self):
250        """
251        deselect objects that have been selected
252        """
253        if self.selMeshObject:
254            self.deselectMeshObject(self.selMeshObject, self.selMeshTag)       
255        if self.selVertex:
256            self.deselectVertex(self.selVertex, self.selVertexTag)
257         
258       
259    def selectZoom(self, tag):
260        """
261        Zoom in or out of the current mesh view
262        """
263        fraction = string.atof(tag)
264        self.SCALE *= fraction
265        self.scrolledcanvas.scale(ALL, 0, 0, fraction, fraction)
266
267        # Redraw all of the vertices, holes and regions,
268        #so the squares representing vertices
269        # don't get bigger
270        vertices = self.mesh.getUserVertices()
271        holes = self.mesh.getHoles()
272        regions = self.mesh.getRegions()
273        MeshObjects  = vertices + holes + regions
274        for obj in MeshObjects:
275            self.canvas.delete(obj.guiID)
276            if self.selVertex == obj:
277                obj.draw(self.canvas,obj.guiID,  scale =self.SCALE ,colour= VERT_SELECT_ADDING_SEG_COLOR)
278            elif self.selMeshObject == obj:
279                obj.draw(self.canvas,obj.guiID,  scale =self.SCALE ,colour= SELECT_COLOR)
280            else:
281                obj.draw(self.canvas,obj.guiID,  scale =self.SCALE ) 
282       
283        top, bottom = self.scrolledcanvas.xview()
284        xcenter  = (top + bottom)/2
285        xdiff =  xcenter - top 
286        xcnew = xcenter - xdiff/fraction
287       
288        top, bottom = self.scrolledcanvas.yview()
289        ycenter = (top + bottom)/2
290        ydiff = ycenter - top
291        ycnew = ycenter - ydiff/fraction
292       
293        self.scrolledcanvas.resizescrollregion()
294        # update so the moveto calls will work...
295        self.scrolledcanvas.update()
296        # but calling update now does make things jerky
297        self.canvas.xview_moveto(xcnew)
298        self.canvas.yview_moveto(ycnew)
299       
300   
301    def windowAddVertex (self, parent):
302        """
303        add a vertex using a window and entering x y values.
304
305        the parent attribute isn't used by this function.
306        need to userstand toolbarbutton.py to know how to
307        get rid of it.
308        """
309       
310        dialog = AddVertexDialog(self.canvas)
311        if dialog.xyValuesOk:
312            print dialog.x
313            print dialog.y
314            self.drawVertex(dialog.x*self.SCALE,dialog.y*self.SCALE,None)
315            #Since the new vertex may be off screen
316            self.ResizeToFit()
317   
318    def windowDefault (self, parent):
319        """
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        # self.UserMesh is a vMesh instance
326        self.UserMesh.defaultWindow(self.canvas, self.curModeClass)
327   
328    def windowEdit (self, parent):
329        """
330
331        the parent attribute isn't used by this function.
332        need to userstand toolbarbutton.py to know how to
333        get rid of it.
334        """
335        if self.selMeshObject:   
336            self.UserMeshChanged = self.UserMesh.editWindow(self.canvas,
337                                     self.selMeshObject,
338                                     self.UserMeshChanged)
339   
340   
341    def autoSegmentButton (self, parent):
342        self.autoSegment()
343       
344    def autoSegment (self):
345        """
346        add Segments to bound all vertices
347       
348        the parent attribute isn't used by this function.
349        need to userstand toolbarbutton.py to know how to
350        get rid of it.
351        """
352        if len(self.mesh.getUserVertices()) >= 3:
353            newsegs = self.mesh.autoSegment()
354            for segment in newsegs:
355                self.serial +=1
356                self.uniqueID = 'M*%d' % self.serial
357                self.Segments.visualise(segment,
358                                        self.uniqueID,
359                                        self.canvas,
360                                        self.SCALE)
361        else:
362            showerror('pMesh',
363                      'Three or more vetices are needed to be able to autosegment.')
364
365
366    def joinVerticesButton (self, parent):
367        self.joinVertices()
368       
369    def joinVertices (self):
370        """
371        add Segments to connect all vertices
372       
373        the parent attribute isn't used by this function.
374        need to userstand toolbarbutton.py to know how to
375        get rid of it.
376        """
377        if len(self.mesh.getUserVertices()) >= 3:
378            newsegs = self.mesh.joinVertices()
379            for segment in newsegs:
380                self.serial +=1
381                self.uniqueID = 'M*%d' % self.serial
382                self.Segments.visualise(segment,
383                                        self.uniqueID,
384                                        self.canvas,
385                                        self.SCALE)
386        else:
387            showerror('pMesh',
388                      'Three or more vetices are needed to be able to join vertices.')
389       
390    def windowMeshGen (self, parent):
391        """
392        The parent attribute isn't used by this function.
393        need to understand toolbarbutton.py to know how to
394        get rid of it.
395        """
396        # Put exceptions round things.
397        #catch failure in self.mesh.generateMesh
398        dialog = MeshGenDialog(self.canvas,
399                               self.MeshMinAngle,
400                               self.MeshMaxArea,
401                               self.MeshnumTriangles,
402                               self.MeshMaxAreaLast)
403       
404        if dialog.ValuesOk:
405            print dialog.minAngle
406            print dialog.maxArea
407           
408            self.clearSelections()
409            self.canvas.delete(ALL)
410            if dialog.goodMaxArea == True:
411                self.MeshMinAngle = dialog.minAngle
412                self.MeshMaxArea = dialog.maxArea
413                self.MeshMaxAreaLast = True
414               
415                self.mesh = self.MeshGenAreaAngle (dialog.minAngle,
416                                          dialog.maxArea,
417                                          self.mesh)
418            elif dialog.goodNumTriangles == True:
419                self.MeshMinAngle = dialog.minAngle
420                self.MeshnumTriangles  = dialog.numTriangles
421                self.MeshMaxAreaLast = False
422               
423                self.mesh = self.MeshGenAreaNumTriangles (dialog.minAngle,
424                                          dialog.numTriangles,
425                                          self.mesh)
426            else:
427                pass
428            print "userMeshChanged = False"
429            self.UserMeshChanged = False
430            self.visualiseMesh(self.mesh)
431            print "Mesh Generation finished"
432           
433    def MeshGenAreaAngle (self, minAngle, maxArea, mesh):
434        """
435        Generate a mesh, given a minAngle and max area
436        """
437        tempMesh = mesh
438        try:
439            tempMesh.generateMesh(mode = "pzq"+str(minAngle)
440                                  +"a"+str(maxArea)
441                                  +"a") #So areas for regions will be used
442        except AttributeError : # can't catch PyEval_RestoreThread
443            # This doesn't catch tempMesh.generateMesh failing
444            tempMesh = mesh
445        return tempMesh
446       
447
448    def MeshGenAreaNumTriangles (self, minAngle, numTriangles, mesh):
449        """
450        Generate a mesh, given a minAngle and rough # of triangles
451        """
452        #get big triangles
453        #calc area
454        #calc max triangle area
455        #
456        tempMesh = mesh
457        try:
458            tempMesh.generateMesh("pzq1")
459        except AttributeError : # can't catch PyEval_RestoreThread
460            # This doesn't catch tempMesh.generateMesh failing
461            pass
462        meshArea = 0
463        for triangle in tempMesh.getTriangulation():
464             meshArea += triangle.calcArea()
465        print "meshArea: ", meshArea
466
467        maxArea = meshArea/numTriangles
468
469       
470        return self.MeshGenAreaAngle (minAngle,
471                                      maxArea,
472                                      self.mesh)
473       
474    def mouseDown(self, event):
475        """
476        On a mouse down event, depending on the current state,
477        either add a vertex or a seg etc
478        """
479        self.curObject = None
480        self.lastx = self.startx = self.canvas.canvasx(event.x)
481        #The screen canvas has y 'flipped'.  -1* unflips it
482        self.lasty = self.starty = -1*self.canvas.canvasy(event.y)
483        print "----------------------"
484        self.mouseDownCurFunc( self.lastx,
485                               self.lasty,event) #!!! remove the event?
486                                                 # do last
487   
488    def rightMouseUp(self, event):
489        """
490        On a right mouse button up event select the nearest object.
491        """
492        found=False
493        if event.widget.find_withtag(CURRENT): # if there's a widget with a tag
494            [tag,string] = self.canvas.gettags(CURRENT) # get a list of them
495            print "tag",tag  #tags ('M*1008', 'current')
496            if tag[:2] == 'M*':   #!!! this can be removed when there are
497                #    only mesh objects on screen
498                #key, value = string.split(tag, '*')
499                objectID = tag
500                print "Found!! objectID:", objectID
501               
502                meshObjects = self.getAllUserMeshObjects()
503                # It may be a triangle, which is ignored
504                if meshObjects.hasKey(objectID):
505                    selMeshObject = meshObjects.getMeshObject(objectID)
506                    found = True
507                    print "Found! selMeshObject", selMeshObject
508                    #Only select one object at a time
509                    if self.selMeshObject:
510                        self.deselectMeshObject(self.selMeshObject, self.selMeshTag)
511                    self.selectMeshObject(selMeshObject,objectID)
512
513    def getAllUserMeshObjects(self):
514        return self.UserMesh
515       
516    def DeleteSelectedMeshObject(self, event):
517        """
518        if an object is selected, delete it.
519        """
520        if self.selMeshObject:
521            #an object is selected
522            #first deselect the vertex, for selecting a segment
523            if self.selVertex:
524                self.deselectVertex(self.selVertex, self.selVertexTag)
525            ObjectsToVisuallyDelete = self.mesh.deleteMeshObject (self.selMeshObject)
526            for drawOb in ObjectsToVisuallyDelete:
527                self.UserMesh.unvisualise(drawOb, self.canvas)
528               
529            self.selMeshObject = None
530            self.selMeshTag = None
531           
532    def selectMeshObject(self, meshObject, objectID):
533        """
534        selected a mesh object.
535        """
536        self.canvas.delete(objectID)
537        self.selMeshObject = meshObject
538        self.selMeshTag = objectID
539        meshObject.draw(self.canvas,objectID, scale =self.SCALE ,colour = SELECT_COLOR)
540   
541    def deselectMeshObject(self, meshObject, objectID):
542        """
543        deselected a mesh object.
544        """
545        self.canvas.delete(objectID)
546        self.selMeshObject = None
547        self.selMeshTag = None
548        if isinstance(meshObject, mesh.Segment):
549            meshObject.draw(self.canvas,objectID,
550                        scale =self.SCALE ,colour = SEG_COLOUR)
551        else:
552            meshObject.draw(self.canvas,objectID,
553                        scale =self.SCALE )
554           
555    def drag(self,x,y,event):
556        """
557        Hack function.  called when in select and left mouse goes down
558        """
559        pass
560   
561    def drawVertex(self,x,y,event):
562        """
563        draw a vertex object, plus add it to the mesh data structure
564
565        event isn't used
566        """
567        self.serial +=1
568        self.uniqueID = 'M*%d' % self.serial
569        vert = self.Vertices.draw(x,y,self.mesh,self.uniqueID,self.SCALE,self.canvas,event)
570        self.UserMeshChanged = True
571        return vert
572     
573    def drawHole(self,x,y,event):
574        """
575        draw a hole object, plus add it to the mesh data structure
576
577        event isn't used
578        """
579        self.serial +=1
580        self.uniqueID = 'M*%d' % self.serial
581        self.userMeshChanged = True
582        hole = self.Holes.draw(x,y,self.mesh,self.uniqueID,self.SCALE,self.canvas,event)
583        return hole   
584   
585    def drawRegion(self,x,y,event):
586        """
587        draw a region object, plus add it to the mesh data structure
588
589        event isn't used
590        """
591        self.serial +=1
592        self.uniqueID = 'M*%d' % self.serial
593        region = self.Regions.draw(x,y,self.mesh,self.uniqueID,self.SCALE,self.canvas,event)
594        return region
595   
596    def selectSegmentPoint(self,x,y, event):
597        """
598        logic when selecting a vertex object to add a segment
599        """
600        found=False
601        if event.widget.find_withtag(CURRENT): # if there's a widget with a tag
602            [tag,string] = self.canvas.gettags(CURRENT) # get a list of them
603            print "tag",tag  #tags ('M*1008', 'current')
604            objectID = tag
605            #print "Found!! objectID:", objectID
606            if self.Vertices.hasKey(objectID): #isinstance(self.meshObjects[objectID],mesh.Vertex):
607                vertex = self.Vertices.getMeshObject(objectID)
608                found = True
609                print "Found! vertex", vertex
610           
611        if found and self.selVertex == vertex:
612            print "The selected vertex has already been selected"
613            #The selected vertex has already been selected
614            # therefore deselect it
615            self.deselectVertex(self.selVertex, self.selVertexTag)
616            found = False
617                 
618        if found: 
619            #A vertex has been selected!
620            if self.selVertex:
621                if self.mesh.isUserSegmentNew(self.selVertex,vertex):
622                    #vertex is the 2nd vertex
623                    self.drawSegment(vertex,self.selVertex)
624                    self.deselectVertex(self.selVertex, self.selVertexTag)
625                    self.selectVertex(vertex,objectID)
626            else:
627                print "vertex is the 1st vertex" 
628                #vertex is the 1st vertex
629                self.selectVertex(vertex,objectID)
630        else:
631            print " There are no widgets.  This happen's too much"
632                   
633
634    def selectVertex(self, vertex,objectID):
635        """
636        select a vertex object when adding a segment
637        """
638        self.canvas.delete(objectID)
639        self.selVertex = vertex
640        self.selVertexTag = objectID
641        vertex.draw(self.canvas,objectID, scale =self.SCALE ,colour = VERT_SELECT_ADDING_SEG_COLOR)
642   
643    def deselectVertex(self, vertex,objectID):
644        """
645        deselect a vertex object when adding a segment
646        """
647        self.canvas.delete(objectID)
648        self.selVertex = None
649        self.selVertexTag = None
650        vertex.draw(self.canvas,objectID,  scale =self.SCALE )
651         
652    def drawSegment(self,v1,v2):
653        """
654        Create a seg object, draw it and add it to the mesh data structure
655        """
656        self.serial +=1
657        self.uniqueID = 'M*%d' % self.serial
658        self.userMeshChanged = True
659        seg = self.Segments.draw(v1,v2,self.mesh,self.uniqueID,self.SCALE,self.canvas,None)
660        return seg
661
662    def visualiseMesh(self,mesh):
663        """
664        visualise vertices, segments, triangulation, holes
665        """
666        for triangle in mesh.getTriangulation():
667            self.serial +=1
668            self.uniqueID = 'M*%d' % self.serial
669            self.Triangles.visualise(triangle,
670                                    self.uniqueID,
671                                    self.canvas,
672                                    self.SCALE)
673        for segment in mesh.getUserSegments():
674            self.serial +=1
675            self.uniqueID = 'M*%d' % self.serial
676            self.Segments.visualise(segment,
677                                    self.uniqueID,
678                                    self.canvas,
679                                    self.SCALE)
680        for vertex in mesh.getUserVertices():
681            self.serial +=1
682            self.uniqueID = 'M*%d' % self.serial
683            self.Vertices.visualise(vertex,
684                                    self.uniqueID,
685                                    self.canvas,
686                                    self.SCALE)
687           
688        for hole in mesh.getHoles():
689            self.serial +=1
690            self.uniqueID = 'M*%d' % self.serial
691            self.Holes.visualise(hole,
692                                    self.uniqueID,
693                                    self.canvas,
694                                    self.SCALE)   
695        for region in mesh.getRegions():
696            self.serial +=1
697            self.uniqueID = 'M*%d' % self.serial
698            self.Regions.visualise(region,
699                                    self.uniqueID,
700                                    self.canvas,
701                                    self.SCALE)
702    def normalise4ObjMesh(self):
703        if self.mesh:
704            self.clearSelections()
705            self.canvas.delete(ALL)
706            self.mesh.normaliseMesh(400,-200,20)
707            self.visualiseMesh(self.mesh)
708            self.ResizeToFit()
709            self.ResizeToFit()
710           
711    def normaliseMesh(self):
712        if self.mesh:
713            self.clearSelections()
714            self.canvas.delete(ALL)
715            self.mesh.normaliseMesh(1,0,1)
716            self.visualiseMesh(self.mesh)
717            self.ResizeToFit()
718            self.ResizeToFit()
719           
720       
721    def clearMesh(self):
722        """Clear the current mesh object, and the canvas """
723       
724        self.clearSelections()
725        self.canvas.delete(ALL)
726        self.deleteMesh()
727        self.initData()
728        self.createMesh()
729
730    def exportObj(self):
731        fileType = "obj"
732        fileTypeDesc = "obj mesh"
733       
734        ofile = tkFileDialog.asksaveasfilename(filetypes=[(fileTypeDesc, fileType),
735                                                ("All Files", "*")])
736        if ofile:
737            addOn = "." + fileType
738            jumpback = - len(addOn)
739            if ofile[jumpback:] != addOn: 
740                ofile = ofile + addOn
741            try:
742                self.mesh.exportASCIIobj(ofile)
743            except IOError:
744                showerror('Export ASCII file',
745                                   'Can not write to file.')
746            except RuntimeError:
747                showerror('Export ASCII file',
748                                   'No triangulation to export.')
749
750   
751
752    def ImportUngenerate(self):
753        ofile = tkFileDialog.askopenfilename(initialdir=self.currentPath,
754                                             filetypes=[ ("ungenerated polygon information", "txt"),
755                                           ("All Files", "*")])
756        if ofile == "":
757            # The user cancelled the loading action
758            return
759       
760        try:
761            self.clearSelections()
762            self.canvas.delete(ALL)
763            dict = mesh.importUngenerateFile(ofile)
764            self.mesh.addVertsSegs(dict)
765           
766        except SyntaxError: 
767            #this is assuming that the SyntaxError is thrown in
768            #loadxyafile
769            showerror('File error',
770                      ofile + ' is not in the correct format.')
771        except IOError: 
772            #!!! this error type can not be thrown?
773            showerror('File error',
774                      'file ' + ofile + ' could not be found.')
775        except RuntimeError: 
776            showerror('File error',
777                  'file ' + ofile + ' has an unknown file type.')
778   
779        self.visualiseMesh(self.mesh)
780        self.ResizeToFit()
781       
782    def exportASCIIsegmentoutlinefile(self):
783        fileType = "tsh"
784        fileTypeDesc = "text mesh"
785       
786        ofile = tkFileDialog.asksaveasfilename(filetypes=[(fileTypeDesc, fileType),
787                                                ("All Files", "*")])
788        if ofile:
789            addOn = "." + fileType
790            jumpback = - len(addOn)
791            if ofile[jumpback:] != addOn: 
792                ofile = ofile + addOn
793            try:
794                self.mesh.exportASCIIsegmentoutlinefile(ofile)
795            except IOError:
796                showerror('Export ASCII file',
797                                   'Can not write to file.')
798
799    def exportxyafile(self):
800        fileType = "xya"
801        fileTypeDesc = "text vertices"
802       
803        ofile = tkFileDialog.asksaveasfilename(filetypes=[(fileTypeDesc, fileType),
804                                                ("All Files", "*")])
805        if ofile:
806            addOn = "." + fileType
807            jumpback = - len(addOn)
808            if ofile[jumpback:] != addOn: 
809                ofile = ofile + addOn
810            try:
811                self.mesh.exportxyafile(ofile)
812            except IOError:
813                showerror('Export ASCII file',
814                                   'Can not write to file.')
815                               
816    def exportTriangulation(self):
817        """
818        This function is not used?
819        """
820        fileType = "tsh"
821        fileTypeDesc = "text mesh"
822       
823        ofile = tkFileDialog.asksaveasfilename(filetypes=[(fileTypeDesc, fileType),
824                                                ("All Files", "*")])
825        if ofile:
826            addOn = "." + fileType
827            jumpback = - len(addOn)
828            if ofile[jumpback:] != addOn: 
829                ofile = ofile + addOn
830            try:
831                self.mesh.exportASCIItrianglulationfile(ofile)
832            except IOError:
833                showerror('Export ASCII file',
834                                   'Can not write to file.')
835            except RuntimeError:
836                showerror('Export ASCII file',
837                                   'No triangulation to export.')
838               
839   
840    def exportMesh(self):
841        fileType = "tsh"
842        fileTypeDesc = "text Mesh"
843       
844        ofile = tkFileDialog.asksaveasfilename(filetypes=[(fileTypeDesc, fileType),
845                                                ("All Files", "*")])
846        if ofile:
847            addOn = "." + fileType
848            jumpback = - len(addOn)
849            if ofile[jumpback:] != addOn: 
850                ofile = ofile + addOn
851            try:
852                self.mesh.exportASCIImeshfile(ofile)
853            except IOError:
854                showerror('Export ASCII file',
855                                   'Can not write to file.')
856            except RuntimeError:
857                showerror('Export ASCII file',
858                                   'No mesh to export.')
859                   
860    def importFile(self):
861        """
862        import mesh data from a variety of formats (currently 2!)
863        """
864        print "self.currentPath",self.currentPath
865        ofile = tkFileDialog.askopenfilename(initialdir=self.currentPath,
866                                             filetypes=[ ("text Mesh", "tsh"),
867                                                         ("points", "xya"),
868                                           ("All Files", "*")])
869        if ofile == "":
870            # The user cancelled the loading action
871            return
872       
873        try:
874            newmesh = mesh.importMeshFromFile(ofile)
875            self.currentPath, dummy = os.path.split(ofile)
876            print "be good self.currentPath",self.currentPath
877            self.currentFilePathName = ofile
878            self.clearMesh()
879            self.mesh = newmesh
880            self.visualiseMesh(self.mesh)
881            self.ResizeToFit()
882       
883        except SyntaxError: 
884            #this is assuming that the SyntaxError is thrown in
885            #loadxyafile
886            showerror('File error',
887                      ofile + ' is not in the correct format.')
888        except IOError: 
889            #!!! this error type can not be thrown?
890            showerror('File error',
891                      'file ' + ofile + ' could not be found.')
892        except RuntimeError: 
893            showerror('File error',
894                  'file ' + ofile + ' has an unknown file type.')
895        # Could not get the file name to showup in the title
896        #appname =  ofile + " - " + APPLICATION_NAME
897        #print "appname",appname
898       
899       
900   
901    def ResizeToFitWrapper(self, Parent):
902        """
903        The parent attribute isn't used by this function.
904        need to understand toolbarbutton.py to know how to
905        get rid of it.
906        """
907        self.ResizeToFit()
908       
909    def ResizeToFit(self):
910        """Visualise the mesh so it fits in the window"""
911        if self.mesh.getUserVertices() == []:
912            return #There are no vertices!
913        # Resize the window
914        self.scrolledcanvas.resizescrollregion()
915        # I need this so the xview values are correct
916        self.scrolledcanvas.update()
917       
918        xtop, xbottom = self.scrolledcanvas.xview()
919        ytop, ybottom = self.scrolledcanvas.yview()
920        xdiff = xbottom-xtop
921        ydiff = ybottom-ytop
922        if xdiff == 1 and xdiff == 1:
923            #The mesh might be too small.
924            #Make it too large, then resize
925            #!!! Recursive hack.  Should be a better way
926            fraction = 50
927            self.SCALE *= fraction
928            self.scrolledcanvas.scale(ALL, 0, 0, fraction, fraction)
929            self.ResizeToFit()
930        else:
931            # without 0.99 some of the mesh may be off screen
932            fraction = 0.99*min(xdiff,ydiff) 
933            self.selectZoom(fraction)
934           
935    def saveDrawing(self):
936        """
937        Save the current drawing
938        """
939        #print "dsg!!! self.currentFilePathName ",self.currentFilePathName
940        if (self.currentFilePathName[-4:] != ".tsh"):
941            # force user to choose a name
942            self.saveAsDrawing()
943        #self.exportASCIItrianglulationfile(self.currentFilePathName)
944
945    def saveAsDrawing(self):
946        """
947        Save the current drawing, prompting for a file name
948        """
949        ofile = tkFileDialog.asksaveasfilename(initialdir=self.currentPath,
950                                               filetypes=[("text mesh", "tsh"),
951                                             ("All Files", "*")])
952        print "aa"
953        if ofile:
954            if ofile[-4:] == ".tsh": 
955                self.currentFilePathName = ofile
956            else:
957                self.currentFilePathName = ofile + ".tsh"
958            self.exportASCIItrianglulationfile(self.currentFilePathName)
959
960    def exportASCIItrianglulationfile(self,currentFilePathName):
961        """
962        Have a warning prompt when saving a mesh where the generated mesh is
963        different from the user mesh - eg boundary tags that aren't carried
964        thru. Warning ~"Mesh not generated after changes.  Generate mesh?  "
965        - cancel, don't gen, don't save.  Yes - generate mesh, go to save
966        screen.  No - goto save screen.  To implement this need to know when
967        the user has done a change, and the mesh hasn't been generated.  If
968        there is no generated mesh do not prompt.
969        """
970        print "self.UserMeshChanged",self.UserMeshChanged
971        print "self.mesh.isTriangulation()",self.mesh.isTriangulation()
972        if (self.UserMeshChanged) and self.mesh.isTriangulation():
973           
974            m = _show("Warning",
975                                   "A triangulation has not been generated, after mesh changes.  Generate triangulation before saving?",
976                                   icon=QUESTION, 
977                                   type=YESNOCANCEL)
978            if m == "no":
979                self.mesh.exportASCIItrianglulationfile(currentFilePathName)
980                self.UserMeshChanged = False
981            elif m == "cancel":
982                pass
983            elif m == "yes":
984                self.windowMeshGen(None)
985                self.mesh.exportASCIItrianglulationfile(currentFilePathName)
986        else:
987            self.mesh.exportASCIItrianglulationfile(currentFilePathName)
988            self.UserMeshChanged = False
989           
990    def initData(self):
991        """
992        Initialise various lists and flags
993        """
994        self.serial      = 1000
995        self.currentFilePathName = 'untitled'
996
997        # these are attributes I've added
998        self.SCALE       = 1
999        self.selVertex   = None     #The last vertex selected, in draw seg mode
1000        self.selVertexTag   = None     # The selected vertex drawn object tag
1001        self.mesh        = None
1002        self.MeshMinAngle = 20
1003        self.MeshMaxArea = 200
1004        self.MeshnumTriangles = 20
1005        self.MeshMaxAreaLast = False
1006        self.selMeshObject = None  # The mesh object selected in the current mode
1007        self.selMeshTag = None
1008        mesh.Segment.set_default_tag("")
1009        self.UserMeshChanged = False
1010   
1011    def ipostscript(self):
1012        """
1013        Print the canvas as a postscript file
1014        """
1015        ofile = tkFileDialog.asksaveasfilename(filetypes=[("postscript", "ps"),
1016                                             ("All Files", "*")]) 
1017        if ofile:
1018            if ofile[-3:] != ".ps": 
1019                ofile = ofile + ".ps"
1020            postscript = self.canvas.postscript()
1021            fd = open(ofile, 'w')
1022            fd.write(postscript)
1023            fd.close()
1024       
1025    def close(self):
1026        self.quit()
1027
1028    def createInterface(self):
1029        """
1030        Call all functions that create the GUI interface
1031        """
1032        self.initData()
1033        self.createMesh()
1034        AppShell.AppShell.createInterface(self)
1035        self.createButtons()
1036        self.createMenus()
1037        self.createBase()
1038        self.createTools()
1039        self.createZooms()
1040        self.createEdits()
1041        #self.addVertsAndSegs() # !!!DSG start pmesh with a triangle
1042        self.selectFunc('pointer')
1043        self.currentPath = os.getcwd() 
1044
1045    def loadtestmesh(self,ofile):
1046        """
1047        debugging script to test loading a file
1048        """
1049        fd = open(ofile)
1050        a = mesh.Vertex (-10.0, 0.0)
1051        d = mesh.Vertex (0.0, 4.0)
1052        f = mesh.Vertex (4.0,0.0)
1053        g = mesh.Vertex (-5.0,5.0)
1054       
1055        s1 = mesh.Segment(a,d)
1056        s2 = mesh.Segment(d,f)
1057        s3 = mesh.Segment(a,f)
1058
1059        r1 = mesh.Region(0.3, 0.3)
1060       
1061        m = mesh.Mesh(userVertices=[a,d,f,g], userSegments=[s1,s2,s3], regions=[r1] )
1062       
1063        fd.close()
1064        print 'returning m'
1065        return oadtestmesh(ofile)
1066         
1067class  AddVertexDialog(Dialog):
1068    """
1069    Dialog box for adding a vertex by entering co-ordindates
1070    """
1071    def body(self, master):
1072        """
1073        GUI description
1074        """
1075        self.title("Add New Vertex")
1076       
1077        Label(master, text='X position:').grid(row=0, sticky=W)
1078        Label(master, text='Y position:').grid(row=1, sticky=W)
1079
1080        self.xstr   = Entry(master, width = 16, name ="entry")
1081        self.ystr  = Entry(master, width = 16)
1082       
1083        self.xstr.grid(row=0, column=1, sticky=W)
1084        self.ystr.grid(row=1, column=1, sticky=W)
1085
1086        self.= 0
1087        self.= 0
1088        self.xyValuesOk = False
1089       
1090
1091    def apply(self):
1092        """
1093        check entered values
1094        """
1095        try:
1096            self.x = float(self.xstr.get())
1097            self.y = float(self.ystr.get())
1098            self.xyValuesOk = True
1099           
1100        except ValueError:
1101            showerror('Bad Vertex values',
1102                                   'X Y values are not numbers.')
1103
1104
1105class  MeshGenDialog(Dialog):
1106    """
1107    Dialog box for generating a mesh
1108    """
1109    # initial values, hard coded.
1110    # should be values associated with the current mesh
1111    lastMinAngle = 20
1112    lastMaxArea  = 100
1113
1114
1115    def __init__(self,
1116                 parent,
1117                 minAngle,
1118                 maxArea,
1119                 numTriangles,
1120                 MeshMaxAreaLast):
1121        self.minAngle = minAngle
1122        self.maxArea = maxArea
1123        self.numTriangles = numTriangles
1124        self.MeshMaxAreaLast = MeshMaxAreaLast
1125
1126        Dialog.__init__(self, parent)
1127
1128       
1129    def body(self, master):
1130        """
1131        GUI description
1132        """
1133        self.title("Generate Mesh")
1134       
1135        Label(master,
1136              text='Minimum Angle(0 - 40):').grid(row=0, sticky=W)
1137        Label(master,
1138              text='Angles>33 may not converge').grid(row=1, sticky=W)
1139        Label(master, text='Maximum Area:').grid(row=2, sticky=W)
1140        Label(master, text='OR # of triangles:').grid(row=3, sticky=W)
1141
1142
1143        minAngleVar = StringVar()
1144        minAngleVar.set(self.minAngle)
1145        self.minAnglestr   = Entry(master,
1146                                   width = 16,
1147                                   textvariable = minAngleVar,
1148                                   takefocus=1)
1149        if (self.MeshMaxAreaLast):
1150            maxAreaVar = StringVar()
1151            maxAreaVar.set(self.maxArea)
1152            self.maxAreastr  = Entry(master,
1153                                     textvariable = maxAreaVar,
1154                                     width = 16)   
1155            self.numTrianglesstr  = Entry(master,
1156                                          width = 16) 
1157        else: 
1158            self.maxAreastr  = Entry(master,
1159                                     width = 16)
1160            numTrianglesVar = StringVar()
1161            numTrianglesVar.set(self.numTriangles)   
1162            self.numTrianglesstr  = Entry(master,
1163                                          textvariable = numTrianglesVar,
1164                                          width = 16) 
1165
1166
1167        self.minAnglestr.grid(row=0, column=1, sticky=W)
1168        self.maxAreastr.grid(row=2, column=1, sticky=W)
1169        self.numTrianglesstr.grid(row=3, column=1, sticky=W)
1170
1171        self.numTriangles = 0
1172        self.minAngle  = 0
1173        self.maxArea  = 0
1174        self.ValuesOk = False
1175
1176
1177    def apply(self):
1178        """
1179        check entered values
1180        """
1181        self.goodMaxArea = self.goodNumTriangles = True
1182        self.ValuesOk = True
1183        try:
1184            self.minAngle = float(self.minAnglestr.get())
1185            MeshGenDialog.lastMinAngle =self.minAngle
1186        except ValueError:
1187            self.ValuesOk = False
1188            showerror('Bad mesh generation values',
1189                                   ' Values are not numbers.')
1190       
1191        try:   
1192            self.maxArea = float(self.maxAreastr.get())
1193            MeshGenDialog.lastMaxArea =self.maxArea
1194        except ValueError:
1195            self.goodMaxArea = False
1196         
1197        try:   
1198            self.numTriangles = int(self.numTrianglesstr.get())
1199            MeshGenDialog.lastNumTriangles =self.numTriangles
1200        except ValueError:
1201            self.goodNumTriangles= False
1202
1203        if self.goodMaxArea == False and self.goodNumTriangles == False:
1204            self.ValuesOk = False
1205            showerror('Bad mesh generation values',
1206                      'Values are not numbers.')
1207
1208        if self.goodMaxArea == True and self.goodNumTriangles == True:
1209            self.ValuesOk = False
1210            showerror('Bad mesh generation values',
1211                      'Give a maximum area OR number of triangles, not both.')
1212
1213        try: 
1214            # value checking
1215            if self.minAngle <0.0 or self.minAngle >40.0:
1216                raise IOError
1217            if self.goodMaxArea == True and self.maxArea <0.0:
1218                raise IOError
1219            if self.goodNumTriangles == True and self.numTriangles <=0:
1220                raise IOError
1221           
1222        except IOError:
1223            self.ValuesOk = False
1224            showerror('Bad mesh generation values',
1225                                   'Values are out of range.')
1226     
1227if __name__ == '__main__':
1228    draw = Draw()
1229    draw.run()
1230
Note: See TracBrowser for help on using the repository browser.