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

Last change on this file since 390 was 349, checked in by duncan, 21 years ago

adding pmesh

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