Changeset 3228


Ignore:
Timestamp:
16/01/08 12:25:18 (12 years ago)
Author:
mkochan
Message:

Creates correct folders and timespans for all 3 views. Added configurable lengths of time spans for logical date/time transforms, using Pythons "datetime" module.

Location:
DPPP/kml/csml2kml
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • DPPP/kml/csml2kml/python/convertor.py

    r3223 r3228  
    6464                # Instantiate a GridSeriesKML object with this information 
    6565                gsKML = kmlfeatures.GridSeriesKML( 
    66                     self.config, self.csmlFilename, name, description, bBox, timeSteps, timeBounds 
     66                    self.config, viewConfig, self.csmlFilename,  
     67                    name, description, bBox, timeSteps, timeBounds 
    6768                    ) 
    6869 
  • DPPP/kml/csml2kml/python/kmlfeatures.py

    r3223 r3228  
    33import string 
    44import re 
     5from datetime import datetime 
    56from cElementTree import ElementTree, Element, SubElement 
    67from configuration import Configuration 
    78 
    8  
    99class GridSeriesKML(object): 
    1010    ''' Represents a CSML GridSeriesFeature in KML (via WMS requests).''' 
    1111     
    12     def __init__(self, config, parentFilename, name, description, bBox, timeSteps, timeBounds): 
     12    def __init__(self, config, viewConfig, parentFilename, name, description, bBox, timeSteps, timeBounds): 
    1313        ''' Initialise with the key information content''' 
    1414 
    15         # Feature conversion configuration 
     15        # Conversion configuration 
    1616        self.config = config 
     17 
     18        # View-specific conversion configuration (determines how data will be presented) 
     19        self.splitTimeStepsBy = viewConfig.find('SplitTimeStepsBy').text 
     20        ldttText = viewConfig.find('LogicalDateTimeTransform').text 
     21        if ldttText == '20_CENTURY_DECADE': 
     22            self.logicalDateTimeTransform = get20CenturyDecade 
     23        elif ldttText == 'SAME_DATE': 
     24            self.logicalDateTimeTransform = getSameDate 
     25        elif ldttText == 'FIRST_DAY_OF_MONTH': 
     26            self.logicalDateTimeTransform = getFirstDayOfMonth 
     27        else: 
     28            raise ValueError('Config error: Unsupported date/time transform') 
     29 
     30        ldtdText = viewConfig.find('LogicalDateTimeDelta').text 
     31        if ldtdText == 'MONTH_HENCE': 
     32            self.logicalDateTimeDelta = getMonthHence 
     33        elif ldtdText == 'YEAR_HENCE': 
     34            self.logicalDateTimeDelta = getYearHence 
     35        elif ldtdText == 'DECADE_HENCE': 
     36            self.logicalDateTimeDelta = getDecadeHence 
     37        else: 
     38            raise ValueError('Config error: Unsupported date/time delta') 
    1739 
    1840        # Name of the CSML file in which feature is contained 
     
    3456        self.timeBounds=timeBounds.split() 
    3557     
    36     def _getYMD(self, timestep): 
    37         matchObject = re.match("(\d+)\-(\d+)\-(\d+)T", timestep) 
     58    def getYMD(self, timeStep): 
     59        matchObject = re.match("(\d+)\-(\d+)\-(\d+)T", timeStep) 
    3860        (sYear, sMonth, sDay) = matchObject.groups() 
    39         return (sYear, sMonth, sDay) 
    40  
    41     def _getLogicalTimeSpan(self, timestep, logicalYearTransform): 
    42         '''Translate timestep to a timespan that covers a full month in a year 
    43            corresponding to the decade (e.g. 1900s -> 0, 1980s -> 8 
     61        return (int(sYear), int(sMonth), int(sDay)) 
     62 
     63    def getLogicalTimeSpan(self, timeStep): 
     64        ''' Get time span that corresponds to this timeStep by using the appropriate 
     65            date/time transform and delta (i.e. date/time difference) 
    4466        ''' 
    45         matchObject = re.match("(\d+)\-(\d+)\-(\d+)T", timestep) 
    46         (sYear, sMonth, sDay) = matchObject.groups() 
    47         year = int(sYear) 
    48         year = logicalYearTransform(year) 
    49         month = int(sMonth) 
    50         startDate = "%04d-%02d-%02d" % (year, month, 1) 
    51         if month+1 <= 12: 
    52             endDate = "%04d-%02d-%02d" % (year, month+1, 1) 
    53         else: 
    54             endDate = "%04d-%02d-%02d" % (year+1, 1, 1) 
    55        
    56         return (startDate, endDate) 
    57  
    58     def _longitudeWithinMinusPlus180(self, x): 
     67        (year, month, day) = self.getYMD(timeStep) 
     68        dateTime = datetime(year, month, day) 
     69        startDateTime = self.logicalDateTimeTransform(dateTime) 
     70        endDateTime = self.logicalDateTimeDelta(startDateTime) 
     71        return (startDateTime, endDateTime) 
     72 
     73    def longitudeWithinMinusPlus180(self, x): 
    5974        ''' Put the x coordinate within bounds of the period (-180, 180)''' 
    6075        if x != 180: 
     
    6277        return x 
    6378     
    64     def _buildWMSRequest(self, timeStep): 
     79    def buildWMSRequest(self, timeStep): 
    6580        ''' Build a WMS request ''' 
    6681 
     
    86101        # If required, make sure the longitude part of the bounding box is within (-180, 180) 
    87102        if c.get('LongitudeBounds') == 'MINUS_180_TO_PLUS_180': 
    88             self.bBox.east = self._longitudeWithinMinusPlus180(self.bBox.east) 
    89             self.bBox.west = self._longitudeWithinMinusPlus180(self.bBox.west) 
     103            self.bBox.east = self.longitudeWithinMinusPlus180(self.bBox.east) 
     104            self.bBox.west = self.longitudeWithinMinusPlus180(self.bBox.west) 
    90105         
    91106        wmsRequest = '%s?request=GetMap&amp;SERVICE=%s&amp;FORMAT=%s&amp;LAYERS=%s&amp;BBOX=%s&amp;WIDTH=%s&amp;HEIGHT=%s&amp;CRS=%s&TIME=%s' % (url, serviceVersion, imageFormat, layerName, self.bBox.str(), imageWidth, imageHeight, crs, timeStep) 
     
    95110    def exportFeature(self, viewConfig): 
    96111        ''' method to output KML as ElementTree instance - returns a 'Folder' element which can be put into a KML Document element ''' 
    97          
    98         # Analyze view configuration -- this determines how data will be presented 
    99         splitBy = viewConfig.find('SplitTimeStepsBy').text 
    100  
    101         lytText = viewConfig.find('LogicalYearTransform').text 
    102         if lytText == 'DECADES_SINCE_1900': 
    103             logicalYearTransform = getDecadeSince1900 
    104         else: 
    105             logicalYearTransform = getSameYear 
    106112 
    107113        featureElement=Element('Folder') 
     
    110116        SubElement(featureElement, 'visibility').text='0' 
    111117 
    112         if splitBy == None: 
     118        if self.splitTimeStepsBy == None: 
    113119 
    114120            for timeStep in self.timeSteps: 
    115                 goElement = self.buildGroundOverlayElement(timeStep, logicalYearTransform) 
     121                goElement = self.buildGroundOverlayElement(timeStep) 
    116122                featureElement.append(goElement) 
    117123 
     
    119125             
    120126            def getCategory(timeStep): 
    121                 (sYear, sMonth, sDay) = self._getYMD(timeStep) 
    122                 if splitBy == None: 
     127                (year, month, day) = self.getYMD(timeStep) 
     128                if self.splitTimeStepsBy == None: 
    123129                    return timeStep 
    124                 elif splitBy == 'year': 
    125                     return int(sYear) 
    126                 elif splitBy == 'month': 
    127                     return int(sMonth) 
     130                elif self.splitTimeStepsBy == 'year': 
     131                    return year 
     132                elif self.splitTimeStepsBy == 'month': 
     133                    return month 
    128134 
    129135            dict = {} 
     
    143149                SubElement(categoryElement, 'visibility').text='0'         
    144150                for timeStep in dict[category]: 
    145                     goElement = self.buildGroundOverlayElement(timeStep, logicalYearTransform) 
     151                    goElement = self.buildGroundOverlayElement(timeStep) 
    146152                    categoryElement.append(goElement) 
    147153                featureElement.append(categoryElement) 
     
    149155        return featureElement 
    150156 
    151     def buildGroundOverlayElement(self, timeStep, logicalYearTransform): 
     157    def buildGroundOverlayElement(self, timeStep): 
    152158 
    153159        goElement=Element('GroundOverlay')       
     
    157163 
    158164        timespanElement=SubElement(goElement, 'TimeSpan') 
    159         (startTime, endTime) = self._getLogicalTimeSpan(timeStep, logicalYearTransform) 
    160         SubElement(timespanElement, 'begin').text=startTime 
    161         SubElement(timespanElement, 'end').text=endTime 
     165        (startDateTime, endDateTime) = self.getLogicalTimeSpan(timeStep) 
     166        SubElement(timespanElement, 'begin').text = ('%04d-%02d-%02d') % startDateTime.utctimetuple()[0:3] 
     167        SubElement(timespanElement, 'end').text = ('%04d-%02d-%02d') % endDateTime.utctimetuple()[0:3] 
    162168 
    163169        # Include the WMS service call address 
    164170        iconElement=SubElement(goElement,'icon') 
    165         SubElement(iconElement, 'href').text=self._buildWMSRequest(timeStep) 
     171        SubElement(iconElement, 'href').text=self.buildWMSRequest(timeStep) 
    166172        SubElement(iconElement, 'refreshMode').text='onExpire' 
    167173 
     
    174180        return goElement 
    175181 
    176 # ---------- These are defined *outside* the class -- i.e. they are plain functions  
    177  
    178 def getDecadeSince1900(year): 
    179     return (year - 1900) / 10  # get decade as a "logical" year 
    180  
    181 def getSameYear(year): 
    182     return year 
    183  
    184 # ----------------- 
     182# ------------------------- Logical date/time transforms (defined as plain functions) -------------------------- 
     183 
     184def getSameDate(dateTime): return dateTime 
     185 
     186def getFirstDayOfMonth(dateTime): 
     187    replDay = 1 
     188    return dateTime.replace(day=replDay) 
     189 
     190def get20CenturyDecade(dateTime): 
     191    replYear = (dateTime.year - 1900) / 10 + 1 # get decade as a "logical" year 
     192    replDay = 1                                # start month on the 1st of month (not 15th) 
     193    return dateTime.replace(year=replYear, day=replDay) 
     194 
     195# --------------------------- Logical date/time deltas (defined as plain functions) --------------------------- 
     196 
     197def getMonthHence(dateTime): 
     198    if dateTime.month+1  <= 12: 
     199        return dateTime.replace(month=dateTime.month+1) 
     200    else: 
     201        return dateTime.replace(year=dateTime.year+1, month=1) 
     202     
     203def getYearHence(dateTime): 
     204    return dateTime.replace(year=dateTime.year+1) 
     205 
     206def getDecadeHence(dateTime): 
     207    return dateTime.replace(year=dateTime.year+10) 
     208 
     209# -------------------------------------------------------------------------------------------------------------- 
  • DPPP/kml/csml2kml/testdata/clim_10.csml2kml.conf.xml

    r3220 r3228  
    1111    <LatitudeBounds>UNCONSTRAINED</LatitudeBounds> 
    1212  </CSMLGridSeriesFeatureWMSRequest> 
    13   <View name="By feature, whole century"> 
     13  <View name="Whole century"> 
    1414    <SplitTimeStepsBy></SplitTimeStepsBy> 
    15     <LogicalYearTransform>DECADES_SINCE_1900</LogicalYearTransform> 
     15    <LogicalDateTimeTransform>20_CENTURY_DECADE</LogicalDateTimeTransform> 
     16    <LogicalDateTimeDelta>MONTH_HENCE</LogicalDateTimeDelta> 
    1617  </View> 
    17   <View name="By feature and decade"> 
     18  <View name="Compare decades"> 
    1819    <SplitTimeStepsBy>year</SplitTimeStepsBy> 
    19     <LogicalYearTransform>IDENTICAL</LogicalYearTransform> 
     20    <LogicalDateTimeTransform>FIRST_DAY_OF_MONTH</LogicalDateTimeTransform> 
     21    <LogicalDateTimeDelta>MONTH_HENCE</LogicalDateTimeDelta> 
    2022  </View> 
    21   <View name="By feature and month"> 
     23  <View name="Compare months"> 
    2224    <SplitTimeStepsBy>month</SplitTimeStepsBy> 
    23     <LogicalYearTransform>IDENTICAL</LogicalYearTransform> 
     25    <LogicalDateTimeTransform>FIRST_DAY_OF_MONTH</LogicalDateTimeTransform> 
     26    <LogicalDateTimeDelta>DECADE_HENCE</LogicalDateTimeDelta> 
    2427  </View> 
    2528</CSML2KMLConfig> 
Note: See TracChangeset for help on using the changeset viewer.