source: anuga_core/source/anuga/pmesh/graphical_mesh_generator.py @ 5097

Last change on this file since 5097 was 5097, checked in by duncan, 16 years ago

Tweaks to icons

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