""" NOTES ----- Data is being read into the file correctly. Data is NOT being retrieved correctly when making changes in date. There is a clipping plane problem that is seen (get rid of reset clipping?). Might want to consider fixed minimum and maximum so that data is more understandable. Glyphs are not correct...they are probably not being correctly sized. Want to get text for cities correct instead of them floating on the wrong side of the plane. """ # Allan Spale # CS 526 - Project 3 import Tkinter import tkFont import os import sys import vtk import time import random from vtk.tk.vtkTkRenderWindowInteractor import vtkTkRenderWindowInteractor from array import array global I_TRUE global I_FALSE I_TRUE = 1 I_FALSE = 0 #------------------------- GUI BUILDER CLASSES ----------------------------------- """ This class is more like a factory than an instantiatable class. It helps create Tkinter widgets without a lot of repetitive configuration. """ class GUIFactory: global I_TRUE, I_FALSE def __init__( self ): self.__dictStandardGridSettings = { 'padx':5, 'pady':5, 'sticky':Tkinter.SW} self.__defaultFont = tkFont.Font( size=11 ) def newLabel( self, rootPanel, labelText, dictExtraConfig ): l = Tkinter.Label( rootPanel, font=self.__defaultFont, text=labelText ) if ( self.__isConfigEmpty( dictExtraConfig ) == I_FALSE ): l.config( dictExtraConfig ) return l def newEntry( self, rootPanel, fieldIdentifier, dictExtraConfig ): e = Tkinter.Entry( rootPanel, font=self.__defaultFont, text=fieldIdentifier ) if ( self.__isConfigEmpty( dictExtraConfig ) == I_FALSE ): e.config( dictExtraConfig ) print 'Entry...', e return e def newButton( self, rootPanel, buttonText, buttonCommand, dictExtraConfig ): b = Tkinter.Button( rootPanel, font=self.__defaultFont, text=buttonText, command=buttonCommand ) if ( self.__isConfigEmpty( dictExtraConfig ) == I_FALSE ): b.config( dictExtraConfig ) return b def newCheckbox( self, rootPanel, checkText, checkCommand, dictExtraConfig ): c = Tkinter.Checkbutton( rootPanel, font=self.__defaultFont, text=checkText, command=checkCommand, indicatoron=I_FALSE ) if ( self.__isConfigEmpty( dictExtraConfig ) == I_FALSE ): c.config( dictExtraConfig ) return c def newRadiobutton( self, rootPanel, radioText, radioCommand, sharedVariable, radioValue, dictExtraConfig ): r = Tkinter.Radiobutton( rootPanel, font=self.__defaultFont, text=radioText, command=radioCommand, variable=sharedVariable, value=radioValue, indicatoron=I_FALSE ) if ( self.__isConfigEmpty( dictExtraConfig ) == I_FALSE ): r.config( dictExtraConfig ) return r def newSlider( self, rootPanel, sliderCommand, valueStart, valueEnd, dictExtraConfig ): dictExtraConfig[ 'from' ] = valueStart dictExtraConfig[ 'to' ] = valueEnd dictExtraConfig[ 'orient' ] = Tkinter.HORIZONTAL dictExtraConfig[ 'showvalue' ] = I_FALSE s = Tkinter.Scale( rootPanel ) s.config( dictExtraConfig ) s.bind( '', sliderCommand ) s.bind( '', sliderCommand ) s.bind( '', sliderCommand ) s.bind( '', sliderCommand ) s.bind( '', sliderCommand ) s.bind( '', sliderCommand ) return s def newListbox( self, rootPanel, dictExtraConfig ): dictExtraConfig[ 'selectmode' ] = Tkinter.SINGLE l = Tkinter.Listbox( rootPanel, font=self.__defaultFont ) l.config( dictExtraConfig ) return l def packItem( self, object, gridSettings ): items = self.__dictStandardGridSettings.keys() for x in items: gridSettings[ x ] = self.__dictStandardGridSettings[ x ] object.grid( gridSettings ) def __isConfigEmpty( self, dictConfig ): if ( dictConfig == None ): return I_TRUE elif ( len( dictConfig ) > 0 ): return I_FALSE else: return I_TRUE """ This is a composited widget made from Tkinter.Scale and Tkinter.Label. Class methods are available to allow some level of customizability. """ class SliderWithValue: global I_TRUE, I_FALSE def __init__( self, rootPanel, startValue, endValue ): guiFactory = GUIFactory() #self.count = 0 self.__root = rootPanel self.__frame = Tkinter.Frame( self.__root ) self.__label = guiFactory.newLabel( self.__frame, '', { 'padx':5, 'pady':5, 'anchor':Tkinter.SW, 'width':3, 'justify':Tkinter.RIGHT} ) self.__label.grid(row=0, rowspan=1, column=0, columnspan=3, sticky=Tkinter.NW ) filler = guiFactory.newLabel( self.__frame, ' ', None ) filler.grid( row=0, rowspan=1, column=3, columnspan=1 ) self.__slider = guiFactory.newSlider( self.__frame, self.__updateLabel, startValue, endValue, {} ) self.__slider.grid( row=0, rowspan=1, column=4, columnspan=3, sticky=Tkinter.NE) self.__slider.set( startValue ) self.__modified = I_FALSE self.__sliderValue = startValue self.__updateLabel() def addSliderCommandBinding( self, callback ): self.__slider.bind( '', callback ) self.__slider.bind( '', callback ) self.__slider.bind( '', callback ) self.__slider.bind( '', callback ) self.__slider.bind( '', callback ) self.__slider.bind( '', callback ) def configureScale( self, dictConfiguration ): self.__slider.config( dictConfiguration ) def setScaleValue( self, value ): self.__slider.set( value ) self.__updateLabel() def reset( self ): value = self.__slider.cget( 'from' ) self.__slider.set( value ) self.__updateLabel() self.__modified = I_FALSE def configureLabel( self, dictConfiguration ): self.__label.config( dictConfiguration ) def getWidget( self ): return self.__frame def getValue( self ): return self.__slider.get() def getValue2( self ): return int( self.__label.cget( 'text' ) ) def getValue3( self ): return self.__sliderValue def __updateLabel( self, *unusedArgument ): #print self.count, self.__valueLabel #self.count = self.count+1 #self.__label = self.__slider.get() self.__label.config( text=self.__slider.get() ) self.__modified = I_TRUE self.__sliderValue = self.__slider.get() def getModifiedStatus(): return self.__modified """ This is a class that creates a modal dialog. To prevent confusion of having the same dialog appear twice (if the user made a selection that would cause multiple (conflicting) copies of the dialog to appear twice), all dialogs will be modal. All dialog boxes will extend this class. """ class ModalDialog: global I_TRUE, I_FALSE def __init__( self, topWindow, dialogTitle, useStatusBarFlag ): self.__firstTime = I_TRUE self.__buildDialog( topWindow, dialogTitle, useStatusBarFlag ) self.config = {} self.config[ 'text' ] = '' self.config[ 'foreground' ] = '' self.config[ 'background' ] = '' def __buildDialog( self, root, title, statusBarFlag ): self.__rootWindow = root self.__title = title self.__statusBarFlag = statusBarFlag self.__root = Tkinter.Toplevel( self.__rootWindow ) self.__root.title( title ) #self.__root.resizable( 0,0 ) self.dialog = Tkinter.Frame( self.__root ) self.dialog.pack() # constants self.B_USE_ERROR_COLOR = I_TRUE self.B_NO_ERROR_COLOR = I_FALSE """if ( self.__statusBarFlag == I_TRUE ): self.__statusBar = Tkinter.Label( self.__root, relief=Tkinter.SUNKEN, text=' ', justify=Tkinter.LEFT, anchor=Tkinter.W ) self.__statusBar.pack() self.__statusOriginalBGColor = self.__statusBar.cget( 'background' ) self.__statusOriginalFGColor = self.__statusBar.cget( 'foreground' ) """ self.hide() def rebuildDialog( self, newRoot ): self.__rootWindow = newRoot self.__buildDialog( newRoot, self.__title, self.__statusBarFlag ) def show( self ): # modal dialog settings...adopted from "An Introduction to Tkinter" print self.__root.state() if ( self.__firstTime == I_TRUE ): #self.__root.transient( self.__rootWindow ) self.__firstTime = I_FALSE self.__root.deiconify() #self.__root.grab_set() #events sent to this dialog #self.__root.focus_set() #self.__root.wait_window( self.__root ) def destroy( self ): #self.__root.grab_release() self.__root.destroy() def hide( self ): #self.__root.grab_release() #self.__root.withdraw() self.__root.iconify() def setStatusBarMessage( self, useErrorColorFlag, statusText ): if ( self.__statusBarFlag == I_TRUE ): self.config[ 'text' ] = statusText if ( useErrorColorFlag == I_TRUE ): self.config[ 'foreground' ] = '#0000AA' self.config[ 'background' ] = '#FFFFFF' else: self.config[ 'foreground' ] = self.__statusOriginalFGColor self.config[ 'background' ] = self.__statusOriginalBGColor self.__statusBar.config( self.config ) def configStatusBar( self, dictConfiguration ): self.__statusBar.config( dictConfiguration ) #------------------------- GUI BUILDER CLASS ----------------------------------- #------------------------- STATION CLASS ---------------------------------------- class Station: global I_TRUE, I_FALSE # class constants I_AVG_WIND_SPEED = 20 I_AVG_WIND_DIRECTION = 30 I_AVG_AIR_TEMP = 40 I_AVG_4_IN_SOIL_TEMP = 50 I_AVG_HUMIDITY = 60 I_TOTAL_PRECIP = 70 I_MISSING_DATA = -9999999 def __init__( self ): # member variables self.__strCodeName = '???' self.__strFullName = 'Nowhere' self.__hashAvgWindSpeed = {} self.__hashAvgWindDirection = {} self.__hashAvgAirTemp = {} self.__hashAvg4InSoilTemp = {} self.__hashAvgHumidity = {} self.__hashTotalPrecip = {} self.__tupScreenLocation = (0,0) def zSetCodeName( self, strCode ): self.__strCodeName = strCode def strGetCodeName( self ): return self.__strCodeName def zSetFullName( self, strName ): self.__strFullName = strName def strGetFullName( self ): return self.__strFullName def zSetScreenLocation( self, tupLocation ): self.__tupScreenLocation = tupLocation def tupGetScreenLocation( self ): return self.__tupScreenLocation def zAddDataRow( self, intDate, hashDataRow ): print 'Adding row data: ', hashDataRow self.__hashAvgWindSpeed[ intDate ] = hashDataRow[ Station.I_AVG_WIND_SPEED ] self.__hashAvgWindDirection[ intDate ] = hashDataRow[ Station.I_AVG_WIND_DIRECTION ] self.__hashAvgAirTemp[ intDate ] = hashDataRow[ Station.I_AVG_AIR_TEMP ] self.__hashAvg4InSoilTemp[ intDate ] = hashDataRow[ Station.I_AVG_4_IN_SOIL_TEMP ] self.__hashAvgHumidity[ intDate ] = hashDataRow[ Station.I_AVG_HUMIDITY ] self.__hashTotalPrecip[ intDate ] = hashDataRow[ Station.I_TOTAL_PRECIP ] """ print "ADDED VALUES - ", intDate print "=============================" print 'SPEED: ', self.__hashAvgWindSpeed[ intDate ] print 'DIR: ',self.__hashAvgWindDirection[ intDate ] print 'AIR TEMP: ',self.__hashAvgAirTemp[ intDate ] print '4" SOIL: ',self.__hashAvg4InSoilTemp[ intDate ] print 'HUM: ',self.__hashAvgHumidity[ intDate ] print 'PRECIP: ',self.__hashTotalPrecip[ intDate ] time.sleep( 3 ) """ # Returns hash function with data...if fails, return empty hash def hashGetDataRow( self, intDate ): hashData = {} # Just have to test if date exists for one hash data type if ( self.__hashAvgWindSpeed.has_key( intDate ) == I_TRUE ): hashData[ Station.I_AVG_WIND_SPEED ] = self.__hashAvgWindSpeed[ intDate ] hashData[ Station.I_AVG_WIND_DIRECTION ] = self.__hashAvgWindDirection[ intDate ] hashData[ Station.I_AVG_AIR_TEMP ] = self__hashAvgAirTemp[ intDate ] hashData[ Station.I_AVG_4_IN_SOIL_TEMP ] = self.__hashAvg4InSoilTemp[ intDate ] hashData[ Station.I_AVG_HUMIDITY ] = self.__hashAvgHumidity[ intDate ] hashData[ Station.I_TOTAL_PRECIP ] = self.__hashTotalPrecip[ intDate ] else: print 'hashGetDataRow' print 'At station ', self.__strFullName, '...data is not available for date:', intDate return hashData # Request a data item for a specific date def numGetDataItem( self, intDate, intDataType ): print 'Get data item ', intDataType, 'for ', intDate numDataItem = Station.I_MISSING_DATA # Just have to test if date exists for one hash data type if ( self.__hashAvgWindSpeed.has_key( intDate ) == I_TRUE ): if ( intDataType == Station.I_AVG_WIND_SPEED ): numDataItem = self.__hashAvgWindSpeed[ intDate ] elif ( intDataType == Station.I_AVG_WIND_DIRECTION ): numDataItem = self.__hashAvgWindDirection[ intDate ] elif ( intDataType == Station.I_AVG_AIR_TEMP ): numDataItem = self.__hashAvgAirTemp[ intDate ] elif ( intDataType == Station.I_AVG_4_IN_SOIL_TEMP ): numDataItem = self.__hashAvg4InSoilTemp[ intDate ] elif ( intDataType == Station.I_AVG_HUMIDITY ): numDataItem = self.__hashAvgHumidity[ intDate ] elif ( intDataType == Station.I_TOTAL_PRECIP ): numDataItem = self.__hashTotalPrecip[ intDate ] else: print 'Data type ', intDataType, 'does not exist.' else: print 'GET DATA ITEM FOR SPECIFIC DATE' print 'At station ', self.__strFullName, '...data is not available for date:', intDate return numDataItem #------------------------- END OF STATION CLASS ---------------------------------------- #------------------------- STATIONSET CLASS ---------------------------------------- class StationSet: global I_TRUE, I_FALSE # Constants (used to extract data from file) I_YEAR = 0 I_MONTH = 1 I_DAY = 2 I_AVG_WIND_SPEED = 5 I_AVG_WIND_DIRECTION = 7 I_AVG_AIR_TEMP = 15 I_AVG_HUMIDITY = 21 I_TOTAL_PRECIP = 25 I_AVG_4_IN_SOIL_TEMP = 33 I_ERR_AVG_WIND_SPEED = 6 I_ERR_AVG_WIND_DIRECTION = 8 I_ERR_AVG_AIR_TEMP = 16 I_ERR_AVG_HUMIDITY = 22 I_ERR_TOTAL_PRECIP = 26 I_ERR_AVG_4_IN_SOIL_TEMP = 34 CHAR_MISSING_DATA = 'M' __I_EARLIEST_YEAR_CODE = 20031100 def __init__( self ): self.__hashStationToFilename = {} self.__hashStationToDataObject = {} intSuccess = self.iSetupStationFiles( './station-config.txt' ) if ( intSuccess == I_FALSE ): print 'Could not open station-config.txt.' print 'Please make sure that this file appears in the same directory as project3.py.' sys.exit( 1 ) def iSetupStationFiles( self, strConfigFilename ): iStatus = I_FALSE iFileStatus = I_FALSE listItems = [] iStationCount = 0 strFilePath = os.path.normpath( strConfigFilename ) if ( os.path.exists( strFilePath ) == I_TRUE ): iStatus = I_TRUE fileStationData = open( strFilePath, 'r' ) strFileLine = fileStationData.readline() iLineSize = len( strFileLine ) while ( iLineSize > 0 ): listItems = strFileLine.split( ',' ) # Order is assumed: Full Name, Code Name, X Location, Y Location, # Data File Path iFileStatus = self.__iAddNewStation( listItems[ 0 ], listItems[ 1 ], ( int(listItems[ 2 ]), int(listItems[ 3 ]) ), listItems[ 4 ] ) if ( iFileStatus == I_TRUE ): # Read related data file iFileStatus = self.__iSetStationData( listItems[ 1 ] ) if ( iFileStatus == I_TRUE ): iStationCount = iStationCount + 1 else: print 'Error reading data file for', listItems[ 0 ], '.' strFileLine = fileStationData.readline() iLineSize = len( strFileLine ) # end of reading loop fileStationData.close() print 'Added', iStationCount, 'station(s).' # else, nothing return iStatus def hashGetStationNames( self ): hashStations = {} listKeys = self.__hashStationToDataObject.keys() for strItem in listKeys: hashStations[ strItem ] = self.__hashStationToDataObject[ strItem ].strGetFullName() return hashStations def hashGetStationLocations( self ): hashStations = {} listKeys = self.__hashStationToDataObject.keys() for strItem in listKeys: hashStations[ strItem ] = self.__hashStationToDataObject[ strItem ].tupGetScreenLocation() return hashStations def __iSetStationData( self, strCodeName ): iStatus = I_FALSE iLineSize = 0 strFileLine = '' fileStationData = None listDataItems = [] stationCurrent = None hashCurrentData = {} iDateCode = 0 if ( self.__hashStationToFilename.has_key( strCodeName ) == I_TRUE ): stationCurrent = self.__hashStationToDataObject[ strCodeName ] fileStationData = open( self.__hashStationToFilename[ strCodeName ], 'r' ) # Skip first 2 lines because of labels for i in range( 0, 3 ): strFileLine = fileStationData.readline() iLineSize = len( strFileLine ) while ( iLineSize > 0 ): listDataItems = strFileLine.split( ',' ) # Create year integer (YYYYMMDD) iYear = int(listDataItems[ StationSet.I_YEAR ]) iMonth= int(listDataItems[ StationSet.I_MONTH ]) iDay = int(listDataItems[ StationSet.I_DAY ]) iDateCode = iYear * 10000 iDateCode = iDateCode + iMonth * 100 iDateCode = iDateCode + iDay if ( iDateCode > StationSet.__I_EARLIEST_YEAR_CODE ): # Get average wind speed if ( listDataItems[ StationSet.I_ERR_AVG_WIND_SPEED ] == StationSet.CHAR_MISSING_DATA ): hashCurrentData[ Station.I_AVG_WIND_SPEED ] = float( Station.I_MISSING_DATA ) else: hashCurrentData[ Station.I_AVG_WIND_SPEED ] = float( listDataItems[ StationSet.I_AVG_WIND_SPEED ] ) # Get average wind direction if ( listDataItems[ StationSet.I_ERR_AVG_WIND_DIRECTION ] == StationSet.CHAR_MISSING_DATA ): hashCurrentData[ Station.I_AVG_WIND_DIRECTION ] = float( Station.I_MISSING_DATA ) else: hashCurrentData[ Station.I_AVG_WIND_DIRECTION ] = float( listDataItems[ StationSet.I_AVG_WIND_DIRECTION ] ) # Get average air temperature if ( listDataItems[ StationSet.I_ERR_AVG_AIR_TEMP ] == StationSet.CHAR_MISSING_DATA ): hashCurrentData[ Station.I_AVG_AIR_TEMP ] = float( Station.I_MISSING_DATA ) else: hashCurrentData[ Station.I_AVG_AIR_TEMP ] = float( listDataItems[ StationSet.I_AVG_AIR_TEMP ] ) # Get average relative humidity if ( listDataItems[ StationSet.I_ERR_AVG_HUMIDITY ] == StationSet.CHAR_MISSING_DATA ): hashCurrentData[ Station.I_AVG_HUMIDITY ] = float( Station.I_MISSING_DATA ) else: hashCurrentData[ Station.I_AVG_HUMIDITY ] = float( listDataItems[ StationSet.I_AVG_HUMIDITY ] ) # Get total precipitation if ( listDataItems[ StationSet.I_ERR_TOTAL_PRECIP ] == StationSet.CHAR_MISSING_DATA ): hashCurrentData[ Station.I_TOTAL_PRECIP ] = float( Station.I_MISSING_DATA ) else: hashCurrentData[ Station.I_TOTAL_PRECIP ] = float( listDataItems[ StationSet.I_TOTAL_PRECIP ] ) # Get average 4" soil temperature if ( listDataItems[ StationSet.I_ERR_AVG_4_IN_SOIL_TEMP ] == StationSet.CHAR_MISSING_DATA ): hashCurrentData[ Station.I_AVG_4_IN_SOIL_TEMP ] = float( Station.I_MISSING_DATA ) else: hashCurrentData[ Station.I_AVG_4_IN_SOIL_TEMP ] = float( listDataItems[ StationSet.I_AVG_4_IN_SOIL_TEMP ] ) # Place data in "database" stationCurrent.zAddDataRow( iDateCode, hashCurrentData ) # else, do not process data if less than earliest year # Get next data line strFileLine = fileStationData.readline() iLineSize = len( strFileLine ) # End of data reading loop iStatus = I_TRUE fileStationData.close() # End of valid key for processing data else: print 'Station code ', strCodeName, ' does not exist.' return iStatus def hashGetDataTypeForDate( self, intDate, intDataType ): print "Hash get data type ", intDataType, " for date ", intDate hashDateData = {} stationCurrent = None listStations = [] listStations = self.__hashStationToDataObject.keys() for aStation in listStations: stationCurrent = self.__hashStationToDataObject[ aStation ] hashDateData[ aStation ] = stationCurrent.numGetDataItem( intDate, intDataType ) return hashDateData def viewAllData( self ): for date in range( 20031101, 20031131 ): print date print "===============" for type in range( 20, 80, 10 ): print type print "-------" print self.hashGetDataTypeForDate( date, type ) #time.sleep( 1 ) print def __iAddNewStation( self, strFullName, strCodeName, tupLocation, strDataFilename ): iStatus = I_FALSE strFilePath = os.path.normpath( strDataFilename ) if ( os.path.exists( strFilePath ) == I_TRUE ): station = Station() station.zSetCodeName( strCodeName ) station.zSetFullName( strFullName ) station.zSetScreenLocation( tupLocation ) self.__hashStationToFilename[ strCodeName ] = strDataFilename self.__hashStationToDataObject[ strCodeName ] = station print 'Added ', strFullName, ' (', strCodeName, ') at ', tupLocation, ' tied to filename ', strDataFilename iStatus = I_TRUE else: print 'File ' + strDataFilename + ' does not exist.' return iStatus #------------------------- END OF STATIONSET CLASS ---------------------------------------- #------------------------- VTK CLASS ---------------------------------------- class VTKRender: global I_TRUE, I_FALSE # Assumption...clockwise direction for wind measurement HASH_WIND_DIRECTION = { 0.0:'S', 22.5:'SSE', 45.0:'SE', 67.5:'ESE', 90.0:'E', 115.5:'ENE', 135.0:'NE', 157.5:'NNE', 180.0:'N', 202.5:'NNW', 225.0:'NW', 247.5:'WNW', 270.0:'W', 292.5:'WSW', 315.0:'SW', 337.5:'SSW' } # Misc B_USE_RANGE = I_TRUE B_CALCULATED_RANGE = I_FALSE # Visualization types I_NO_VIZ = 0 I_HUMIDITY_VIZ = 100 I_PRECIPITATION_VIZ = 150 I_WIND_VIZ = 200 I_AIR_TEMP_VIZ = 250 I_SOIL_TEMP_VIZ = 300 # Map properties I_MAP_WIDTH = 338 I_MAP_HEIGHT = 599 I_MAP_POINTS = I_MAP_WIDTH * I_MAP_HEIGHT I_MAP_HALF_WIDTH = I_MAP_WIDTH / 2 I_MAP_TYPE_BOUNDARY = 1000 I_MAP_TYPE_COUNTY = 1100 I_MAP_TYPE_ROADS = 1200 # Miscellaneous I_DATE_UNCHANGED = 99999999 F_MAX_FLOAT = 99999999.99 F_MIN_FLOAT = -99999999.99 def __init__(self, frame ): self.__frame = frame self.__zSetupDataStructures() self.__zSetupVizPipelines() def __zSetupDataStructures( self ): self.__iVizType = VTKRender.I_AIR_TEMP_VIZ # Station information self.__vpStationPoints = vtk.vtkPoints() self.__hashStationLocations = {} self.__hashStationNames = {} self.__hashCurrentColormapStationData = {} self.__iColormapStationDataMin = 0 self.__iColormapStationDataMax = 0 self.__hashCurrentGlyphStationData = {} self.__iGlyphStationDataMin = 0 self.__iGlyphStationDataMax = 0 self.vfaGlyphScalarValues = vtk.vtkFloatArray() self.vfaColormapScalarValues = vtk.vtkFloatArray() # City map information self.__listvvtStationText = [] self.__listvpdmStationTextMapper = [] self.__listvaStationTextActor = [] self.__iYear = 2003 self.__iMonth = 11 self.__iDay = 11 self.__iDateCode = 20031101 self.__hashMapNamesAndFiles = { VTKRender.I_MAP_TYPE_COUNTY:'./maps/counties.jpg', VTKRender.I_MAP_TYPE_BOUNDARY:'./maps/border.jpg', VTKRender.I_MAP_TYPE_ROADS:'./maps/roads.jpg' } self.__iMapHeight = 0 self.__iCityLabelHeight = self.__iMapHeight + 1 def __zSetupVizPipelines( self ): ################### MAP PIPELINE ############################# # Map types ###### County ###### Adapted from: http://www.censusfinder.com/mapil.htm self.vjrMapCountyFile = vtk.vtkJPEGReader() self.vjrMapCountyFile.SetFileName( os.path.normpath( self.__hashMapNamesAndFiles[ VTKRender.I_MAP_TYPE_COUNTY ] ) ) ###### State border ###### Adapted from: http://www.sws.uiuc.edu/warm/icnstationmap.asp self.vjrMapStateBorderFile = vtk.vtkJPEGReader() self.vjrMapStateBorderFile.SetFileName( os.path.normpath( self.__hashMapNamesAndFiles[ VTKRender.I_MAP_TYPE_BOUNDARY ] ) ) ###### Roads ###### Adapted from: http://www.mrcusa.com/page4.htm self.vjrMapRoadsFile = vtk.vtkJPEGReader() self.vjrMapRoadsFile.SetFileName( os.path.normpath( self.__hashMapNamesAndFiles[ VTKRender.I_MAP_TYPE_ROADS ] ) ) self.vdsmMapImage = vtk.vtkDataSetMapper() self.vdsmMapImage.SetInput( self.vjrMapCountyFile.GetOutput() ) self.vdsmMapImage.SetScalarRange(0, 255) self.vdsmMapImage.ImmediateModeRenderingOff() self.vaMapActor = vtk.vtkActor() self.vaMapActor.SetMapper( self.vdsmMapImage ) self.vaMapActor.GetProperty().SetOpacity( 1 ) self.vaMapActor.SetPosition( 0,0,self.__iMapHeight ) ############## CITY LABELS PIPELINE ########################## # Taken care of later in self.zSetupStations() """ ################ DATA PREPARATION PIPELINE #################### # self.__vpStationPoints has points added in self.zSetupStations() # self.vpdStationViz.GetPointData().SetScalars( scalars ) # will be done when needed for data for each viz self.vpdColormapStationViz = vtk.vtkPolyData() self.vpdStationViz.SetPoints( self.__vpStationPoints ) """ ############## COLORMAP PIPELINE ############################ # Polydata self.vpdColormapStationViz = vtk.vtkPolyData() self.vpdColormapStationViz.SetPoints( self.__vpStationPoints ) self.vpdColormapStationViz.GetPointData().SetScalars( self.vfaColormapScalarValues ) # Interpolation self.vsmColormapInterpolation = vtk.vtkShepardMethod() self.vsmColormapInterpolation.SetInput( self.vpdColormapStationViz ) self.vsmColormapInterpolation.SetMaximumDistance( 1 ) self.vsmColormapInterpolation.SetModelBounds( 0,VTKRender.I_MAP_WIDTH-1, 0,VTKRender.I_MAP_HEIGHT-1, 0,1 ) self.vsmColormapInterpolation.SetSampleDimensions( VTKRender.I_MAP_WIDTH / 1.5, VTKRender.I_MAP_WIDTH / 1.5, 2 ) self.vsmColormapInterpolation.Update() # Lookup table is adjusted according to each visualization self.vltColormapLookupTable = vtk.vtkLookupTable() # Mapper self.vdsmColormapMapper = vtk.vtkDataSetMapper() self.vdsmColormapMapper.SetInput( self.vsmColormapInterpolation.GetOutput() ) self.vdsmColormapMapper.SetLookupTable( self.vltColormapLookupTable ) # Actor self.vaColormapActor = vtk.vtkActor() self.vaColormapActor.SetMapper( self.vdsmColormapMapper ) ################### GLYPH PIPELINE ########################## # Multiple shape sources for glyphs # Cubes for "bars" in elevation map in precipitation self.vcsGlyphCubeSource = vtk.vtkCubeSource() self.vcsGlyphCubeSource.SetBounds( 0,1, 0,1, 0,5) # Spheres for "clouds" in humidity data and wind speed self.vcsGlyphSphereSource = vtk.vtkSphereSource() self.vcsGlyphSphereSource.SetCenter( 0,0,0 ) self.vcsGlyphSphereSource.SetRadius( 2 ) self.vcsGlyphSphereSource.SetPhiResolution( 5 ) self.vcsGlyphSphereSource.SetStartPhi( -90 ) # Polydata self.vpdGlyphStationViz = vtk.vtkPolyData() self.vpdGlyphStationViz.SetPoints( self.__vpStationPoints ) self.vpdGlyphStationViz.GetPointData().SetScalars( self.vfaGlyphScalarValues ) # Interpolation self.vsmGlyphInterpolation = vtk.vtkShepardMethod() self.vsmGlyphInterpolation.SetInput( self.vpdGlyphStationViz ) self.vsmGlyphInterpolation.SetMaximumDistance( 1 ) self.vsmGlyphInterpolation.SetModelBounds( 0,VTKRender.I_MAP_WIDTH-1, 0,VTKRender.I_MAP_HEIGHT-1, 0,1 ) self.vsmGlyphInterpolation.SetSampleDimensions( VTKRender.I_MAP_WIDTH / 1.5, VTKRender.I_MAP_WIDTH / 1.5, 2 ) self.vsmGlyphInterpolation.Update() # Mask self.vmpGlyphPointMask = vtk.vtkMaskPoints() self.vmpGlyphPointMask.SetInput( self.vsmGlyphInterpolation.GetOutput() ) self.vmpGlyphPointMask.SetOnRatio( 40 ) # Lookup Table is adjusted according to each visualization self.vltGlyphColorLookupTable = vtk.vtkLookupTable() # Glyph 3D # SetSource: Set according to viz; either self.vcsGlyphCubeSource # or self.vcsGlyphSphereSource # SetScaleFactor: Set according to viz self.vg3dGlyph = vtk.vtkGlyph3D() self.vg3dGlyph.SetInput( self.vmpGlyphPointMask.GetOutput() ) self.vg3dGlyph.SetScaleModeToScaleByScalar() # Polydata mapper self.vpdmGlyphMapper = vtk.vtkPolyDataMapper() self.vpdmGlyphMapper.SetInput( self.vg3dGlyph.GetOutput() ) self.vpdmGlyphMapper.SetLookupTable( self.vltGlyphColorLookupTable ) # Actor self.vaGlyphGroupActor = vtk.vtkActor() self.vaGlyphGroupActor.SetMapper( self.vpdmGlyphMapper ) ################ RENDERING PIPELINE ########################## # Renderer self.vrRenderer = vtk.vtkRenderer() self.vrRenderer.SetBackground( 0.329412, 0.34902, 0.427451 ) ###### Add map actor to renderer' self.vrRenderer.AddActor( self.vaMapActor ) # Render window self.vrwRenderWindow = vtk.vtkRenderWindow() self.vrwRenderWindow.AddRenderer( self.vrRenderer ) self.vrwRenderWindow.SetSize( VTKRender.I_MAP_WIDTH, VTKRender.I_MAP_HEIGHT ) # Render interactor self.vrwiWindowControl = vtkTkRenderWindowInteractor( self.__frame, rw=self.vrwRenderWindow, width=VTKRender.I_MAP_WIDTH + 10, height=VTKRender.I_MAP_HEIGHT + 10 ) self.vrwiWindowControl.SetRenderWindow( self.vrwRenderWindow ) self.vrwiWindowControl.pack( side='top', fill='both', expand=1 ) #################### ACTIVATE RENDERING ######################## self.vrwiWindowControl.Initialize() self.vrwiWindowControl.Start() self.vrwRenderWindow.Render() # Store station screen locations def zSetupStations( self, hashStationLocations, hashStationNames ): # Convenience constants X = 0 Y = 1 tupLocation = () self.__hashStationLocations = hashStationLocations self.__hashStationNames = hashStationNames ################# CITY LABELS PIPELINE ########################### self.__vpStationPoints = vtk.vtkPoints() iIndex = 0 listStations= [] strStationLocation = '' # To prevent any potential for data "misalignment" (i.e. being assigned # to the wrong station), sort keys first. listStations = self.__hashStationLocations.keys() listStations.sort() for aStation in listStations: print "list index =",iIndex #time.sleep( 1) # Vector text self.__listvvtStationText.append( vtk.vtkVectorText() ) strStationLocation = 'x\n' + self.__hashStationNames[ aStation ] self.__listvvtStationText[ iIndex ].SetText( strStationLocation ) # Polydata mapper self.__listvpdmStationTextMapper.append( vtk.vtkPolyDataMapper() ) self.__listvpdmStationTextMapper[ iIndex ].SetInput( self.__listvvtStationText[ iIndex ].GetOutput() ) # Follower (sort of acts as an actor) self.__listvaStationTextActor.append( vtk.vtkFollower() ) self.__listvaStationTextActor[ iIndex ].SetMapper( self.__listvpdmStationTextMapper[ iIndex ] ) self.__listvaStationTextActor[ iIndex ].SetScale(10,10,1) # Add station location in __vpStationPoints tupLocation = self.__hashStationLocations[ aStation ] self.__vpStationPoints.InsertPoint( iIndex, tupLocation[ X ], tupLocation[ Y ], 0.0 ) self.__listvaStationTextActor[ iIndex ].AddPosition( tupLocation[ X ], tupLocation[ Y ], 0.0 ) # Update float arrays self.vfaGlyphScalarValues.InsertValue( iIndex, 0.0 ) self.vfaColormapScalarValues.InsertValue( iIndex, 0.0 ) # Add actor to renderer #self.vrRenderer.AddActor( self.__listvaStationTextActor[ iIndex ] ) # Increment index iIndex = iIndex + 1 self.vpdColormapStationViz.SetPoints( self.__vpStationPoints ) self.vpdColormapStationViz.GetPointData().SetScalars( self.vfaColormapScalarValues ) self.vpdGlyphStationViz.SetPoints( self.__vpStationPoints ) self.vpdGlyphStationViz.GetPointData().SetScalars( self.vfaGlyphScalarValues ) self.vsmColormapInterpolation.Update() self.vsmGlyphInterpolation.Update() # Set the map type def zSetMapType( self, iMapID ): print "mapid = ", iMapID if ( iMapID == VTKRender.I_MAP_TYPE_BOUNDARY ): self.vdsmMapImage.SetInput( self.vjrMapStateBorderFile.GetOutput() ) elif ( iMapID == VTKRender.I_MAP_TYPE_COUNTY ): self.vdsmMapImage.SetInput( self.vjrMapCountyFile.GetOutput() ) elif ( iMapID == VTKRender.I_MAP_TYPE_ROADS ): self.vdsmMapImage.SetInput( self.vjrMapRoadsFile.GetOutput() ) else: pass # do nothing # Update render window self.vrwRenderWindow.Render() # Set the viz based on date and data type def zSetDateData( self, iDateCode, iDataType, hashColormapStationData, hashGlyphStationData ): print "SetDateData..." print "date =", iDateCode print "type = ", iDataType print "colormap data = ", hashColormapStationData print "Glyph data = ", hashGlyphStationData ###### TO DO # 0. Map Station type to viz type # 1. Extract date # 2. Get data from StationData # 3. Update city label information # 4. Update viz objects # 5. Update render window # 0. Map station type to viz type self.__iLastVizType = self.__iVizType if ( iDataType == Station.I_AVG_AIR_TEMP ): self.__iVizType = VTKRender.I_AIR_TEMP_VIZ elif ( iDataType == Station.I_AVG_4_IN_SOIL_TEMP ): self.__iVizType = VTKRender.I_AIR_TEMP_VIZ elif ( iDataType == Station.I_AVG_HUMIDITY ): self.__iVizType = VTKRender.I_HUMIDITY_VIZ elif ( iDataType == Station.I_TOTAL_PRECIP ): self.__iVizType = VTKRender.I_PRECIPITATION_VIZ elif ( iDataType == Station.I_AVG_WIND_SPEED ): self.__iVizType = VTKRender.I_WIND_VIZ elif ( iDataType == Station.I_AVG_WIND_SPEED ): self.__iVizType = VTKRender.I_WIND_VIZ else: self.__iVizType = VTKRender.I_NO_VIZ # 1. Extract date if ( iDateCode != VTKRender.I_DATE_UNCHANGED ): self.__iDateCode = iDateCode self.__iYear = self.__iDateCode / 10000 iWorkingDate = self.__iDateCode - self.__iYear * 10000 self.__iMonth = iWorkingDate / 100 iWorkingDate = iWorkingDate - self.__iMonth * 100 self.__iDay = iWorkingDate else: pass # use same date as before # 2. Get data from StationData # hashColormapStationData: Used by air temp, soil temp, wind viz # hashGlyphStationData: Used by humidity, precip, wind # wind is a combo because it uses color for direction & glyph for speed listStations = [] listTempValueArray = [] iIndex = 0 fValue = 0.0 listStations = hashColormapStationData.keys() listStations.sort() iNumberOfStations = len( listStations ) print "STEP 2" # Colormap case if ( ( self.__iVizType == VTKRender.I_AIR_TEMP_VIZ ) or ( self.__iVizType == VTKRender.I_SOIL_TEMP_VIZ ) ): self.vpdColormapStationViz.GetPointData().SetScalars( self.__vfaNormalizeValues( hashColormapStationData, VTKRender.B_CALCULATED_RANGE, 0, 0 ) ) elif ( self.__iVizType == VTKRender.I_WIND_VIZ ): self.vpdColormapStationViz.GetPointData().SetScalars( self.__vfaNormalizeValues( hashColormapStationData, VTKRender.B_USE_RANGE, 0, 360 ) ) #direction print "GLYPH..." # Glyph case if ( self.__iVizType == VTKRender.I_HUMIDITY_VIZ ): self.vpdGlyphStationViz.GetPointData().SetScalars( self.__vfaNormalizeValues( hashGlyphStationData, VTKRender.B_CALCULATED_RANGE, 0, 0 ) ) elif ( self.__iVizType == VTKRender.I_PRECIPITATION_VIZ ): self.vpdGlyphStationViz.GetPointData().SetScalars( self.__vfaNormalizeValues( hashGlyphStationData, VTKRender.B_CALCULATED_RANGE, 0, 0 ) ) elif ( self.__iVizType == VTKRender.I_WIND_VIZ ): self.vpdGlyphStationViz.GetPointData().SetScalars( self.__vfaNormalizeValues( hashGlyphStationData, VTKRender.B_CALCULATED_RANGE, 0, 80 ) ) #speed # 3. Update city label information (value,location text) iIndex = 0 strTemp = '' "STEP 3..." if ( ( self.__iVizType == VTKRender.I_AIR_TEMP_VIZ ) or ( self.__iVizType == VTKRender.I_SOIL_TEMP_VIZ ) ): for station in listStations: self.__listvvtStationText[ iIndex ].SetText( str( hashColormapStationData[ station ] ) + 'F \n' + str( self.__hashStationNames[ station ] ) ) elif ( self.__iVizType == VTKRender.I_HUMIDITY_VIZ): for station in listStations: self.__listvvtStationText[ iIndex ].SetText( str( hashGlyphStationData[ station ] ) + '% \n' + str( self.__hashStationNames[ station ] ) ) elif ( self.__iVizType == VTKRender.I_PRECIPITATION_VIZ ): for station in listStations: self.__listvvtStationText[ iIndex ].SetText( str( hashGlyphStationData[ station ] ) + '\" \n' + str( self.__hashStationNames[ station ] ) ) elif ( self.__iVizType == VTKRender.I_WIND_VIZ ): for station in listStations: # Direction...get text equivalent of degree measurement iDirection = hashColormapStationData[ station ] strDirection = '' if ( iDirection >= 337.5 ): strDirection = 'SSW' elif ( iDirection >= 315.0 ): strDirection = 'SW' elif ( iDirection >= 292.5 ): strDirection = 'WSW' elif ( iDirection >= 270.0 ): strDirection = 'W' elif ( iDirection >= 247.5 ): strDirection = 'WNW' elif ( iDirection >= 225.0 ): strDirection = 'NW' elif ( iDirection >= 202.5 ): strDirection = 'NNW' elif ( iDirection >= 180.0 ): strDirection = 'N' elif ( iDirection >= 157.5 ): strDirection = 'NNE' elif ( iDirection >= 135.0 ): strDirection = 'NE' elif ( iDirection >= 115.5 ): strDirection = 'ENE' elif ( iDirection >= 90.0 ): strDirection = 'E' elif ( iDirection >= 67.5 ): strDirection = 'ESE' elif ( iDirection >= 45.0 ): strDirection = 'SE' elif ( iDirection >= 22.5 ): strDirection = 'SSE' elif ( iDirection >= 0.0 ): strDirection = 'S' else: strDirection = '?' # Speed iSpeed = hashGlyphStationData[ station ] self.__listvvtStationText[ iIndex ].SetText( str( strDirection ) + ' @ ' + str( iSpeed ) + '\n' + str( self.__hashStationNames[ station ] ) ) else: pass # do nothing print "STEP 4" # 4. Update viz objects ###### Remove both actors just to be safe from potential weirdness bValid = I_TRUE self.vrRenderer.RemoveActor( self.vaColormapActor ) self.vrRenderer.RemoveActor( self.vaGlyphGroupActor ) #self.vltColormapLookupTable.SetRange( # self.__iColormapStationDataMin, self.__iColormapStationDataMax ) #self.vltColormapLookupTable.Build() #self.vpdmGlyphMapper.SetScalarRange( # self.__fGlyphStationDataMin, self.__fGlyphStationDataMax ) #>>>self.vpdmGlyphMapper.SetScalarRange( # self.__fGlyphStationDataMin, self.__fGlyphStationDataMax ) #self.vltGlyphColorLookupTable.SetRange( # self.__iGlyphStationDataMin, self.__iGlyphStationDataMax ) self.vltGlyphColorLookupTable.Build() if ( ( self.__iVizType == VTKRender.I_AIR_TEMP_VIZ ) or ( self.__iVizType == VTKRender.I_SOIL_TEMP_VIZ ) ): # Colormap assignment self.vdsmColormapMapper.SetScalarRange( 0,1 ) # Fix lookup table self.vltColormapLookupTable.SetValueRange( 0.5, 1.0 ) self.vltColormapLookupTable.SetHueRange( 0.833, 0.0 ) self.vltColormapLookupTable.SetSaturationRange( 0.5, 1.0 ) self.vltColormapLookupTable.SetAlphaRange( 1.0, 1.0 ) self.vltColormapLookupTable.Build() # Adjust map properties self.__iMapHeight = 2 self.vaMapActor.GetProperty().SetOpacity( 0.5 ) self.__iCityLabelHeight = self.__iMapHeight + 1 #self.vaMapActor.Render( self.vrRenderer, self.vdsmMapImage) self.vdsmMapImage.Update() # Add actor self.vrRenderer.AddActor( self.vaColormapActor ) elif ( self.__iVizType == VTKRender.I_HUMIDITY_VIZ ): # Glyph assignment self.vpdmGlyphMapper.SetScalarRange( 0,1 ) # Fix lookup table self.vltGlyphColorLookupTable.SetValueRange( 0.1, 1.0 ) self.vltGlyphColorLookupTable.SetHueRange( 0.0, 0.0 ) self.vltGlyphColorLookupTable.SetSaturationRange( 0.0, 0.0 ) self.vltGlyphColorLookupTable.SetAlphaRange( 1.0, 0.3 ) self.vltGlyphColorLookupTable.Build() # Adjust map properties self.__iMapHeight = 15 self.vaMapActor.GetProperty().SetOpacity( 0.4 ) self.__iCityLabelHeight = self.__iMapHeight + 1 #self.vaMapActor.Render( self.vrRenderer, self.vdsmMapImage ) self.vdsmMapImage.Update() # Adjust glyph properties self.vcsGlyphSphereSource.SetRadius( 2 ) self.vg3dGlyph.SetScaleFactor( 6 ) self.vg3dGlyph.SetSource( self.vcsGlyphSphereSource.GetOutput() ) # Add actor self.vrRenderer.AddActor( self.vaGlyphGroupActor ) elif ( self.__iVizType == VTKRender.I_PRECIPITATION_VIZ ): # Glyph assignment self.vpdmGlyphMapper.SetScalarRange( 0,1 ) # Fix lookup table self.vltGlyphColorLookupTable.SetValueRange( 1.0, 1.0 ) self.vltGlyphColorLookupTable.SetHueRange( 0.833, 0.333 ) self.vltGlyphColorLookupTable.SetSaturationRange( 1.0, 1.0 ) #self.vltGlyphColorLookupTable.SetAlphaRange( 1.0, 0.1 ) #1.0, 0.6 self.vltGlyphColorLookupTable.Build() # Adjust map properties self.__iMapHeight = 0 self.vaMapActor.GetProperty().SetOpacity( 0.45 ) self.__iCityLabelHeight = self.__iMapHeight + 81 #self.vaMapActor.Render(self.vrRenderer, self.vdsmMapImage ) self.vdsmMapImage.Update() # Adjust glyph properties self.vg3dGlyph.SetScaleFactor( 15 ) self.vg3dGlyph.SetSource( self.vcsGlyphCubeSource.GetOutput() ) # Add actor self.vaGlyphGroupActor.GetProperty().SetOpacity( 0.2 ) self.vrRenderer.AddActor( self.vaGlyphGroupActor ) elif ( self.__iVizType == VTKRender.I_WIND_VIZ ): # Colormap assignment self.vdsmColormapMapper.SetScalarRange( 0,1 ) # Fix colormap lookup table (wind direction) self.vltColormapLookupTable.SetValueRange( 1.0, 1.0 ) self.vltColormapLookupTable.SetHueRange( 0.0, 1.0 ) self.vltColormapLookupTable.SetSaturationRange( 1.0, 1.0 ) self.vltColormapLookupTable.SetAlphaRange( 1.0, 0.3 ) self.vltColormapLookupTable.Build() # Glyph assignment self.vpdmGlyphMapper.SetScalarRange( 0,1 ) # Fix glyph color lookup table (wind speed) self.vltGlyphColorLookupTable.SetValueRange( 0.0, 1.0 ) self.vltGlyphColorLookupTable.SetHueRange( 0.0, 0.0 ) self.vltGlyphColorLookupTable.SetSaturationRange( 0.0, 0.0 ) self.vltGlyphColorLookupTable.SetAlphaRange( 0.7, 0.7 ) self.vltGlyphColorLookupTable.Build() # Adjust glyph properties self.vcsGlyphSphereSource.SetRadius( 1 ) self.vg3dGlyph.SetScaleFactor( 10 ) self.vg3dGlyph.SetSource( self.vcsGlyphSphereSource.GetOutput() ) # Adjust map properties self.__iMapHeight = 15 self.vaMapActor.GetProperty().SetOpacity( 0.45 ) self.__iCityLabelHeight = self.__iMapHeight + 1 #self.vaMapActor.Render(self.vrRenderer, self.vdsmMapImage ) self.vdsmMapImage.Update() # Add actor self.vrRenderer.AddActor( self.vaColormapActor ) self.vrRenderer.AddActor( self.vaGlyphGroupActor ) else: bValid = I_FALSE pass # do nothing ###### Update map height and city label heights if ( bValid == I_TRUE ): print "City label height=", self.__iCityLabelHeight # Convenience constants X = 0 Y = 1 listStations = self.__hashStationLocations.keys() listStations.sort() iIndex = 0 tupLocation = () self.vaMapActor.SetPosition( 0,0, self.__iMapHeight ) for station in listStations: # Get station location tupLocation = self.__hashStationLocations[ station ] iXLocation = tupLocation[ X ] iYLocation = tupLocation[ Y ] # Update point data self.__vpStationPoints.SetPoint( iIndex, tupLocation[ X ], tupLocation[ Y ], self.__iCityLabelHeight ) self.__listvaStationTextActor[ iIndex ].SetPosition( tupLocation[ X ], tupLocation[ Y ], self.__iCityLabelHeight ) self.vrRenderer.RemoveActor( self.__listvaStationTextActor[ iIndex ] ) self.vrRenderer.AddActor( self.__listvaStationTextActor[ iIndex ] ) # end of loop else: pass # do nothing # 5. Update render window self.vrwRenderWindow.Render() self.vsmColormapInterpolation.Update() self.vsmGlyphInterpolation.Update() def __vfaNormalizeValues( self, hashValues, bUseRange, fMin, fMax ): vfaReturnFloatArray = vtk.vtkFloatArray() fValueRange = 0.0 listStations = hashValues.keys() listStations.sort() if ( bUseRange == VTKRender.B_CALCULATED_RANGE ): fMinValue = VTKRender.F_MAX_FLOAT fMaxValue = VTKRender.F_MIN_FLOAT # Find data range for station in listStations: fValue = hashValues[ station ] if ( fValue < fMinValue ): fMinValue = fValue elif ( fValue > fMaxValue ): fMaxValue = fValue else: fMinValue = fMin fMaxValue = fMax # Normalize fValueRange = fMaxValue - fMinValue iIndex= 0 for station in listStations: print 'index: ', iIndex fValue = ( hashValues[ station ] - fMinValue ) / fValueRange print "Value = ", fValue vfaReturnFloatArray.InsertValue( iIndex, fValue ) iIndex = iIndex + 1 return vfaReturnFloatArray def destroy( self ): del self.vrRenderer del self.vrwRenderWindow del self.vrwiWindowControl #------------------------- VTK CLASS ---------------------------------------- #-------------- DATE PICKER DIALOG ------------------------------------------- class DialogDatePicker( ModalDialog ): global I_TRUE, I_FALSE hashDaysInMonth = { 1:31, 2:28, 3:31, 4:30, 5:31, 6:30, 7:31, 8:31, 9:30, 10:31, 11:30, 12:31 } HASH_MONTH_NAME = { 1:'January', 2:'February', 3:'March', 4:'April', 5:'May', 6:'June', 7:'July', 8:'August', 9:'September', 10:'October', 11:'November', 12:'December' } def __init__( self, topWindow, vtkWindow, labelStatus ): ModalDialog.__init__( self, topWindow, 'Date Picker', I_TRUE ) self.__vtkWindow = vtkWindow self.__statusBar = labelStatus self.__hashCurrentColormapData = {} # includes wind direction self.__hashCurrentGlyphData = {} self.__tkintFlag = Tkinter.IntVar() self.__stationSet = StationSet() # >>>>> Test station set hashStations = self.__stationSet.hashGetStationLocations() print "STATION INFORMATION" print hashStations #print "STATION DATA FOR EACH DATE" #print "==========================" #self.__stationSet.viewAllData() self.__strStatusText = '' self.__intStartYear = 0 self.__intStartMonth = 0 self.__intStartDay = 0 self.__intEndYear = 0 self.__intEndMonth = 0 self.__intEndDay = 0 self.__buildDialog() # Get data from StationSet to VTKRender self.__vtkWindow.zSetupStations( self.__stationSet.hashGetStationLocations(), self.__stationSet.hashGetStationNames() ) # Set current viz type self.__intStartDateCode = 20031101 self.__intEndDateCode = 0 self.zSetCurrentVizType( Station.I_AVG_AIR_TEMP ) def iGetStartDate( self ): return self.__intStartDateCode def iGetEndDate( self ): return self.__intEndDateCode def zSetCurrentVizType( self, iVizType ): self.__iCurrentViz = iVizType if ( self.__iCurrentViz == Station.I_AVG_HUMIDITY ): #self.__strStatusText = 'Average Humidity for ' + self.__strStatusText self.__hashCurrentGlyphData = self.__stationSet.hashGetDataTypeForDate( self.__intStartDateCode, self.__iCurrentViz ) print "Glyph humidity:",self.__hashCurrentGlyphData elif ( self.__iCurrentViz == Station.I_TOTAL_PRECIP ): #self.__strStatusText = 'Total Precipitation for ' + self.__strStatusText self.__hashCurrentGlyphData = self.__stationSet.hashGetDataTypeForDate( self.__intStartDateCode, self.__iCurrentViz ) print "Glyph precip:",self.__hashCurrentGlyphData elif ( self.__iCurrentViz == Station.I_AVG_AIR_TEMP): #self.__strStatusText = 'Average Air Temperature for ' + self.__strStatusText self.__hashCurrentColormapData = self.__stationSet.hashGetDataTypeForDate( self.__intStartDateCode, self.__iCurrentViz ) elif ( self.__iCurrentViz == Station.I_AVG_4_IN_SOIL_TEMP ): #self.__strStatusText = 'Average 4" Soil Temperature for ' + self.__strStatusText self.__hashCurrentColormapData = self.__stationSet.hashGetDataTypeForDate( self.__intStartDateCode, self.__iCurrentViz ) elif ( ( self.__iCurrentViz == Station.I_AVG_WIND_SPEED ) or ( self.__iCurrentViz == Station.I_AVG_WIND_DIRECTION ) ): #self.__strStatusText = 'Average Wind Speed and Direction for ' + self.__strStatusText self.__hashCurrentGlyphData = self.__stationSet.hashGetDataTypeForDate( self.__intStartDateCode, Station.I_AVG_WIND_SPEED ) self.__hashCurrentColormapData = self.__stationSet.hashGetDataTypeForDate( self.__intStartDateCode, Station.I_AVG_WIND_DIRECTION ) print "Glyph wind direction:",self.__hashCurrentGlyphData else: self.__iCurrentViz = VTKRender.I_NO_VIZ if ( self.__iCurrentViz != VTKRender.I_NO_VIZ ): self.__statusBar.config( text=self.__strStatusText ) self.zUpdateViz() def zUpdateViz( self ): if ( ( self.__iCurrentViz == Station.I_AVG_HUMIDITY ) or ( self.__iCurrentViz == Station.I_TOTAL_PRECIP ) ): self.__hashCurrentGlyphData = self.__stationSet.hashGetDataTypeForDate( self.__intStartDateCode, self.__iCurrentViz ) elif ( ( self.__iCurrentViz == Station.I_AVG_AIR_TEMP ) or ( self.__iCurrentViz == Station.I_AVG_4_IN_SOIL_TEMP ) ): self.__hashCurrentColormapData = self.__stationSet.hashGetDataTypeForDate( self.__intStartDateCode, self.__iCurrentViz ) elif ( ( self.__iCurrentViz == Station.I_AVG_WIND_SPEED ) or ( self.__iCurrentViz == Station.I_AVG_WIND_DIRECTION ) ): self.__hashCurrentGlyphData = self.__stationSet.hashGetDataTypeForDate( self.__intStartDateCode, Station.I_AVG_WIND_SPEED ) self.__hashCurrentColormapData = self.__stationSet.hashGetDataTypeForDate( self.__intStartDateCode, Station.I_AVG_WIND_DIRECTION ) else: self.__iCurrentViz = VTKRender.I_NO_VIZ if ( self.__iCurrentViz != VTKRender.I_NO_VIZ ): self.__statusBar.config( text=self.__strStatusText ) self.__vtkWindow.zSetDateData( self.__intStartDateCode, self.__iCurrentViz, self.__hashCurrentColormapData, self.__hashCurrentGlyphData ) def __buildDialog( self ): guiFactory = GUIFactory() gridSettings = { 'padx':5, 'pady':5, 'sticky':Tkinter.SW, 'row':0, 'rowspan':1, 'column':0, 'columnspan':1 } # Start date ###### Start label """labelStart = guiFactory.newLabel( self.dialog, 'Start', {'justify':Tkinter.CENTER} ) gridSettings[ 'row' ] = 0 gridSettings[ 'rowspan' ] = 1 gridSettings[ 'column' ] = 0 gridSettings[ 'columnspan' ] = 3 guiFactory.packItem( labelStart, gridSettings ) """ ###### Year slider labelStartYear = guiFactory.newLabel( self.dialog, 'Year', {'justify':Tkinter.LEFT} ) gridSettings[ 'row' ] = 1 gridSettings[ 'column' ] = 0 gridSettings[ 'columnspan' ] = 1 guiFactory.packItem( labelStartYear, gridSettings ) self.__sliderStartYear = SliderWithValue( self.dialog, 2000, 2003 ) self.__sliderStartYear.addSliderCommandBinding( self.__doUpdateStartSlider ) self.__widgetStartYear = self.__sliderStartYear.getWidget() gridSettings[ 'column' ] = 1 gridSettings[ 'columnspan' ] = 2 guiFactory.packItem( self.__widgetStartYear, gridSettings ) ###### Month slider labelStartMonth = guiFactory.newLabel( self.dialog, 'Month', {'justify':Tkinter.LEFT} ) gridSettings[ 'row' ] = 2 gridSettings[ 'column' ] = 0 gridSettings[ 'columnspan' ] = 1 guiFactory.packItem( labelStartMonth, gridSettings ) self.__sliderStartMonth = SliderWithValue( self.dialog, 1, 12 ) self.__sliderStartMonth.addSliderCommandBinding( self.__doUpdateStartSlider ) self.__widgetStartMonth = self.__sliderStartMonth.getWidget() gridSettings[ 'column' ] = 1 gridSettings[ 'columnspan' ] = 2 guiFactory.packItem( self.__widgetStartMonth, gridSettings ) ###### Day slider labelStartDay = guiFactory.newLabel( self.dialog, 'Day', {'justify':Tkinter.LEFT} ) gridSettings[ 'row' ] = 3 gridSettings[ 'column' ] = 0 gridSettings[ 'columnspan' ] = 1 guiFactory.packItem( labelStartDay, gridSettings ) self.__sliderStartDay = SliderWithValue( self.dialog, 1, 31 ) self.__sliderStartDay.addSliderCommandBinding( self.__doUpdateStartSlider ) self.__widgetStartDay = self.__sliderStartDay.getWidget() gridSettings[ 'column' ] = 1 gridSettings[ 'columnspan' ] = 2 guiFactory.packItem( self.__widgetStartDay, gridSettings ) ###### Default values self.__sliderStartMonth.setScaleValue( 11 ) self.__sliderStartDay.setScaleValue( 1 ) self.__sliderStartYear.setScaleValue( 2003 ) def __doUpdateStartSlider( self, *unusedArgument ): self.__intStartYear = self.__sliderStartYear.getValue() self.__intStartMonth = self.__sliderStartMonth.getValue() self.__intStartDay = self.__sliderStartDay.getValue() self.__sliderStartYear.configureLabel( { 'text':self.__intStartYear } ) self.__sliderStartMonth.configureLabel( { 'text':self.__intStartMonth } ) self.__sliderStartDay.configureLabel( { 'text':self.__intStartDay } ) self.__validateDate() self.__intStartDateCode = self.__intStartYear * 10000 self.__intStartDateCode = self.__intStartDateCode + ( self.__intStartMonth * 100 ) self.__intStartDateCode = self.__intStartDateCode + self.__intStartDay strMonth = DialogDatePicker.HASH_MONTH_NAME[ self.__intStartMonth ] self.__strStatusText = strMonth + ' ' + str( self.__intStartDay ) + ', ' + str( self.__intStartYear ) #strDate = strMonth.join( ' ' ).join( str( self.__intStartDay ) ).join( # ', ' ).join( str( self.__intStartYear ) ) self.__statusBar.config( text=self.__strStatusText ) # Update data in render window... self.__hashCurrentDateData = self.__stationSet.hashGetDataTypeForDate( self.__intStartDateCode, self.__iCurrentViz ) self.zUpdateViz() #self.__vtkWindow.zUpdateRenderWindow() def __validateDate( self ): intMaxDaysThisMonth = DialogDatePicker.hashDaysInMonth[ self.__intStartMonth ] # Does not take into account year 2000 is a leap year just because # it is divisible by 400 if ( self.__intStartMonth == 2 ): if ( self.__intStartYear % 4 == 0 ): intMaxDaysThisMonth = 29 if ( intMaxDaysThisMonth < self.__intStartDay ): self.__intStartDay = intMaxDaysThisMonth self.__sliderStartDay.setScaleValue( intMaxDaysThisMonth ) # Force all months to be November and all years to be 2003 self.__sliderStartMonth.setScaleValue( 11 ) self.__sliderStartYear.setScaleValue( 2003 ) #----------------------- END OF DATE PICKER DIALOG -------------------------------- #------------------------ GUI CLASS --------------------------------------- class GUI: def __init__( self, rootWindow ): global I_TRUE, I_FALSE # variables self.__tkintViz = Tkinter.IntVar() self.__tkintMap = Tkinter.IntVar() guiFactory = GUIFactory() # Create window frame self.__rootWindow = rootWindow self.__rootWindow.title( 'CS 526, Project 3' ) frameMain = Tkinter.Frame( self.__rootWindow ) frameMain.pack( fill=Tkinter.BOTH, expand=1, side=Tkinter.LEFT ) # Add VTK rendering viewport [automatic packing] self.__vtkViewport = VTKRender( frameMain ) # Add menu bar menuBar = Tkinter.Menu( frameMain ) self.__rootWindow.config( menu=menuBar ) self.__buildMenu( menuBar ) print 'Add menu bar' #<<<< # Add pseudo-status bar (from "An Introduction to Tkinter" ) self.__statusLabel = guiFactory.newLabel( frameMain, 'by: Allan Spale', {'relief':Tkinter.SUNKEN,'justify':Tkinter.CENTER, 'anchor':Tkinter.W } ) self.__statusErrorSettings = { 'background':'#ffffff', 'foreground':'#000099' } self.__statusOKSettings = { 'background':self.__statusLabel.cget( 'background' ), 'foreground':self.__statusLabel.cget( 'foreground' ) } self.__statusLabel.pack( fill=Tkinter.BOTH, side=Tkinter.BOTTOM ) print 'Done with window' #<<<< # Setup date picker dialog self.__dialogDatePicker = DialogDatePicker( self.__rootWindow, self.__vtkViewport, self.__statusLabel ) # Initialize #self.__vtkViewport.zSetupVTKPipeline() self.__tkintViz.set( Station.I_AVG_AIR_TEMP ) self.__tkintMap.set( VTKRender.I_MAP_TYPE_COUNTY ) def __buildMenu( self, menuMainMenu ): menuFile = Tkinter.Menu( menuMainMenu, tearoff=0 ) menuFile.add_command( label='Exit', command=self.__doMenuFileExit ) menuMainMenu.add_cascade( label='File', menu=menuFile ) self.__menuData = Tkinter.Menu( menuMainMenu, tearoff=0 ) self.__menuData.add_radiobutton( label='4" Soil Temperature', value=Station.I_AVG_4_IN_SOIL_TEMP, variable=self.__tkintViz, command=self.__doSetVizType ) self.__menuData.add_radiobutton( label='Air Temperature', value=Station.I_AVG_AIR_TEMP, variable=self.__tkintViz, command=self.__doSetVizType ) self.__menuData.add_radiobutton( label='Humidity', value=Station.I_AVG_HUMIDITY, variable=self.__tkintViz, command=self.__doSetVizType ) self.__menuData.add_radiobutton( label='Precipitation', value=Station.I_TOTAL_PRECIP, variable=self.__tkintViz, command=self.__doSetVizType ) self.__menuData.add_radiobutton( label='Wind', value=Station.I_AVG_WIND_SPEED, variable=self.__tkintViz, command=self.__doSetVizType ) menuMainMenu.add_cascade( label='Data', menu=self.__menuData ) self.__menuMaps = Tkinter.Menu( menuMainMenu, tearoff=0 ) self.__menuMaps.add_radiobutton( label='County', value=VTKRender.I_MAP_TYPE_COUNTY, variable=self.__tkintMap, command=self.__doSetMapType ) self.__menuMaps.add_radiobutton( label='Roads', value=VTKRender.I_MAP_TYPE_ROADS, variable=self.__tkintMap, command=self.__doSetMapType ) self.__menuMaps.add_radiobutton( label='State Border', value=VTKRender.I_MAP_TYPE_BOUNDARY, variable=self.__tkintMap, command=self.__doSetMapType ) menuMainMenu.add_cascade( label='Maps', menu=self.__menuMaps ) def __doSetVizType( self ): print "Viz = ", self.__tkintViz self.__dialogDatePicker.zSetCurrentVizType( self.__tkintViz.get() ) def __doSetMapType( self ): self.__vtkViewport.zSetMapType( self.__tkintMap.get() ) pass def __doMenuFileExit( self ): print 'Bye' self.__vtkViewport.destroy() self.__rootWindow.destroy() sys.exit( 0 ) print 'Done' #------------------------ END OF GUI CLASS ---------------------------------- #### main function #### root = Tkinter.Tk() gui = GUI(root) root.mainloop()