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

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

fixed typo

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