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

Last change on this file since 668 was 654, checked in by duncan, 20 years ago

removing prints, getting save working

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        else:
944            self.exportASCIItrianglulationfile(self.currentFilePathName)
945
946    def saveAsDrawing(self):
947        """
948        Save the current drawing, prompting for a file name
949        """
950        ofile = tkFileDialog.asksaveasfilename(initialdir=self.currentPath,
951                                               filetypes=[("text mesh", "tsh"),
952                                             ("All Files", "*")])
953        print "aa"
954        if ofile:
955            if ofile[-4:] == ".tsh": 
956                self.currentFilePathName = ofile
957            else:
958                self.currentFilePathName = ofile + ".tsh"
959            self.exportASCIItrianglulationfile(self.currentFilePathName)
960
961    def exportASCIItrianglulationfile(self,currentFilePathName):
962        """
963        Have a warning prompt when saving a mesh where the generated mesh is
964        different from the user mesh - eg boundary tags that aren't carried
965        thru. Warning ~"Mesh not generated after changes.  Generate mesh?  "
966        - cancel, don't gen, don't save.  Yes - generate mesh, go to save
967        screen.  No - goto save screen.  To implement this need to know when
968        the user has done a change, and the mesh hasn't been generated.  If
969        there is no generated mesh do not prompt.
970        """
971        #print "self.UserMeshChanged",self.UserMeshChanged
972        #print "self.mesh.isTriangulation()",self.mesh.isTriangulation()
973        if (self.UserMeshChanged) and self.mesh.isTriangulation():
974           
975            m = _show("Warning",
976                                   "A triangulation has not been generated, after mesh changes.  Generate triangulation before saving?",
977                                   icon=QUESTION, 
978                                   type=YESNOCANCEL)
979            if m == "no":
980                self.mesh.exportASCIItrianglulationfile(currentFilePathName)
981                self.UserMeshChanged = False
982            elif m == "cancel":
983                pass
984            elif m == "yes":
985                self.windowMeshGen(None)
986                self.mesh.exportASCIItrianglulationfile(currentFilePathName)
987        else:
988            self.mesh.exportASCIItrianglulationfile(currentFilePathName)
989            self.UserMeshChanged = False
990           
991    def initData(self):
992        """
993        Initialise various lists and flags
994        """
995        self.serial      = 1000
996        self.currentFilePathName = 'untitled'
997
998        # these are attributes I've added
999        self.SCALE       = 1
1000        self.selVertex   = None     #The last vertex selected, in draw seg mode
1001        self.selVertexTag   = None     # The selected vertex drawn object tag
1002        self.mesh        = None
1003        self.MeshMinAngle = 20
1004        self.MeshMaxArea = 200
1005        self.MeshnumTriangles = 20
1006        self.MeshMaxAreaLast = False
1007        self.selMeshObject = None  # The mesh object selected in the current mode
1008        self.selMeshTag = None
1009        mesh.Segment.set_default_tag("")
1010        self.UserMeshChanged = False
1011   
1012    def ipostscript(self):
1013        """
1014        Print the canvas as a postscript file
1015        """
1016        ofile = tkFileDialog.asksaveasfilename(filetypes=[("postscript", "ps"),
1017                                             ("All Files", "*")]) 
1018        if ofile:
1019            if ofile[-3:] != ".ps": 
1020                ofile = ofile + ".ps"
1021            postscript = self.canvas.postscript()
1022            fd = open(ofile, 'w')
1023            fd.write(postscript)
1024            fd.close()
1025       
1026    def close(self):
1027        self.quit()
1028
1029    def createInterface(self):
1030        """
1031        Call all functions that create the GUI interface
1032        """
1033        self.initData()
1034        self.createMesh()
1035        AppShell.AppShell.createInterface(self)
1036        self.createButtons()
1037        self.createMenus()
1038        self.createBase()
1039        self.createTools()
1040        self.createZooms()
1041        self.createEdits()
1042        #self.addVertsAndSegs() # !!!DSG start pmesh with a triangle
1043        self.selectFunc('pointer')
1044        self.currentPath = os.getcwd() 
1045
1046    def loadtestmesh(self,ofile):
1047        """
1048        debugging script to test loading a file
1049        """
1050        fd = open(ofile)
1051        a = mesh.Vertex (-10.0, 0.0)
1052        d = mesh.Vertex (0.0, 4.0)
1053        f = mesh.Vertex (4.0,0.0)
1054        g = mesh.Vertex (-5.0,5.0)
1055       
1056        s1 = mesh.Segment(a,d)
1057        s2 = mesh.Segment(d,f)
1058        s3 = mesh.Segment(a,f)
1059
1060        r1 = mesh.Region(0.3, 0.3)
1061       
1062        m = mesh.Mesh(userVertices=[a,d,f,g], userSegments=[s1,s2,s3], regions=[r1] )
1063       
1064        fd.close()
1065        print 'returning m'
1066        return oadtestmesh(ofile)
1067         
1068class  AddVertexDialog(Dialog):
1069    """
1070    Dialog box for adding a vertex by entering co-ordindates
1071    """
1072    def body(self, master):
1073        """
1074        GUI description
1075        """
1076        self.title("Add New Vertex")
1077       
1078        Label(master, text='X position:').grid(row=0, sticky=W)
1079        Label(master, text='Y position:').grid(row=1, sticky=W)
1080
1081        self.xstr   = Entry(master, width = 16, name ="entry")
1082        self.ystr  = Entry(master, width = 16)
1083       
1084        self.xstr.grid(row=0, column=1, sticky=W)
1085        self.ystr.grid(row=1, column=1, sticky=W)
1086
1087        self.= 0
1088        self.= 0
1089        self.xyValuesOk = False
1090       
1091
1092    def apply(self):
1093        """
1094        check entered values
1095        """
1096        try:
1097            self.x = float(self.xstr.get())
1098            self.y = float(self.ystr.get())
1099            self.xyValuesOk = True
1100           
1101        except ValueError:
1102            showerror('Bad Vertex values',
1103                                   'X Y values are not numbers.')
1104
1105
1106class  MeshGenDialog(Dialog):
1107    """
1108    Dialog box for generating a mesh
1109    """
1110    # initial values, hard coded.
1111    # should be values associated with the current mesh
1112    lastMinAngle = 20
1113    lastMaxArea  = 100
1114
1115
1116    def __init__(self,
1117                 parent,
1118                 minAngle,
1119                 maxArea,
1120                 numTriangles,
1121                 MeshMaxAreaLast):
1122        self.minAngle = minAngle
1123        self.maxArea = maxArea
1124        self.numTriangles = numTriangles
1125        self.MeshMaxAreaLast = MeshMaxAreaLast
1126
1127        Dialog.__init__(self, parent)
1128
1129       
1130    def body(self, master):
1131        """
1132        GUI description
1133        """
1134        self.title("Generate Mesh")
1135       
1136        Label(master,
1137              text='Minimum Angle(0 - 40):').grid(row=0, sticky=W)
1138        Label(master,
1139              text='Angles>33 may not converge').grid(row=1, sticky=W)
1140        Label(master, text='Maximum Area:').grid(row=2, sticky=W)
1141        Label(master, text='OR # of triangles:').grid(row=3, sticky=W)
1142
1143
1144        minAngleVar = StringVar()
1145        minAngleVar.set(self.minAngle)
1146        self.minAnglestr   = Entry(master,
1147                                   width = 16,
1148                                   textvariable = minAngleVar,
1149                                   takefocus=1)
1150        if (self.MeshMaxAreaLast):
1151            maxAreaVar = StringVar()
1152            maxAreaVar.set(self.maxArea)
1153            self.maxAreastr  = Entry(master,
1154                                     textvariable = maxAreaVar,
1155                                     width = 16)   
1156            self.numTrianglesstr  = Entry(master,
1157                                          width = 16) 
1158        else: 
1159            self.maxAreastr  = Entry(master,
1160                                     width = 16)
1161            numTrianglesVar = StringVar()
1162            numTrianglesVar.set(self.numTriangles)   
1163            self.numTrianglesstr  = Entry(master,
1164                                          textvariable = numTrianglesVar,
1165                                          width = 16) 
1166
1167
1168        self.minAnglestr.grid(row=0, column=1, sticky=W)
1169        self.maxAreastr.grid(row=2, column=1, sticky=W)
1170        self.numTrianglesstr.grid(row=3, column=1, sticky=W)
1171
1172        self.numTriangles = 0
1173        self.minAngle  = 0
1174        self.maxArea  = 0
1175        self.ValuesOk = False
1176
1177
1178    def apply(self):
1179        """
1180        check entered values
1181        """
1182        self.goodMaxArea = self.goodNumTriangles = True
1183        self.ValuesOk = True
1184        try:
1185            self.minAngle = float(self.minAnglestr.get())
1186            MeshGenDialog.lastMinAngle =self.minAngle
1187        except ValueError:
1188            self.ValuesOk = False
1189            showerror('Bad mesh generation values',
1190                                   ' Values are not numbers.')
1191       
1192        try:   
1193            self.maxArea = float(self.maxAreastr.get())
1194            MeshGenDialog.lastMaxArea =self.maxArea
1195        except ValueError:
1196            self.goodMaxArea = False
1197         
1198        try:   
1199            self.numTriangles = int(self.numTrianglesstr.get())
1200            MeshGenDialog.lastNumTriangles =self.numTriangles
1201        except ValueError:
1202            self.goodNumTriangles= False
1203
1204        if self.goodMaxArea == False and self.goodNumTriangles == False:
1205            self.ValuesOk = False
1206            showerror('Bad mesh generation values',
1207                      'Values are not numbers.')
1208
1209        if self.goodMaxArea == True and self.goodNumTriangles == True:
1210            self.ValuesOk = False
1211            showerror('Bad mesh generation values',
1212                      'Give a maximum area OR number of triangles, not both.')
1213
1214        try: 
1215            # value checking
1216            if self.minAngle <0.0 or self.minAngle >40.0:
1217                raise IOError
1218            if self.goodMaxArea == True and self.maxArea <0.0:
1219                raise IOError
1220            if self.goodNumTriangles == True and self.numTriangles <=0:
1221                raise IOError
1222           
1223        except IOError:
1224            self.ValuesOk = False
1225            showerror('Bad mesh generation values',
1226                                   'Values are out of range.')
1227     
1228if __name__ == '__main__':
1229    draw = Draw()
1230    draw.run()
1231
Note: See TracBrowser for help on using the repository browser.