Changeset 1289


Ignore:
Timestamp:
May 6, 2005, 10:16:02 AM (20 years ago)
Author:
ole
Message:

Resolved conflict arising from UNIX linebreaks

File:
1 edited

Legend:

Unmodified
Added
Removed
  • inundation/ga/storm_surge/pyvolution/util.py

    r1280 r1289  
    22
    33It is also a clearing house for functions that may later earn a module
    4 of their own.
     4of their own. 
    55"""
    66
     
    1717    v2 = v[1]/l
    1818
    19     try:
     19    try:       
    2020        theta = acos(v1)
    2121    except ValueError, e:
     
    3131            theta = 3.1415926535897931
    3232        print 'WARNING (util.py): angle v1 is %f, setting acos to %f '\
    33               %(v1, theta)
    34 
     33              %(v1, theta)   
     34             
    3535    if v2 < 0:
    3636        #Quadrant 3 or 4
     
    4343    """Compute difference between angle of vector x0, y0 and x1, y1.
    4444    This is used for determining the ordering of vertices,
    45     e.g. for checking if they are counter clockwise.
    46 
     45    e.g. for checking if they are counter clockwise. 
     46   
    4747    Always return a positive value
    4848    """
    49 
     49       
    5050    from math import pi
    51 
     51   
    5252    a0 = angle(v0)
    5353    a1 = angle(v1)
     
    5656    if a0 < a1:
    5757        a0 += 2*pi
    58 
     58           
    5959    return a0-a1
    6060
     
    6565
    6666
    67 def point_on_line(x, y, x0, y0, x1, y1):
    68     """Determine whether a point is on a line segment
    69 
     67def point_on_line(x, y, x0, y0, x1, y1): 
     68    """Determine whether a point is on a line segment 
     69   
    7070    Input: x, y, x0, x0, x1, y1: where
    7171        point is given by x, y
    7272        line is given by (x0, y0) and (x1, y1)
    73 
    74     """
    75 
     73       
     74    """
     75       
    7676    from Numeric import array, dot, allclose
    7777    from math import sqrt
    7878
    79     a = array([x - x0, y - y0])
     79    a = array([x - x0, y - y0]) 
    8080    a_normal = array([a[1], -a[0]])
    81 
     81                       
    8282    b = array([x1 - x0, y1 - y0])
    83 
     83   
    8484    if dot(a_normal, b) == 0:
    8585        #Point is somewhere on the infinite extension of the line
    8686
    87         len_a = sqrt(sum(a**2))
    88         len_b = sqrt(sum(b**2))
     87        len_a = sqrt(sum(a**2))               
     88        len_b = sqrt(sum(b**2))                                 
    8989        if dot(a, b) >= 0 and len_a <= len_b:
    9090           return True
    91         else:
     91        else:   
    9292           return False
    9393    else:
    94       return False
    95 
     94      return False 
     95   
    9696def ensure_numeric(A, typecode = None):
    9797    """Ensure that sequence is a Numeric array.
     
    117117        if type(A) == ArrayType:
    118118            if A.typecode == typecode:
    119                 return array(A)
     119                return array(A)           
    120120            else:
    121121                return A.astype(typecode)
    122122        else:
    123123            return array(A).astype(typecode)
    124 
    125 
     124       
     125   
    126126
    127127def file_function(filename, domain=None, quantities = None, interpolation_points = None, verbose = False):
     
    133133    #In fact, this is where origin should be converted to that of domain
    134134    #Also, check that file covers domain fully.
    135 
     135   
    136136    assert type(filename) == type(''),\
    137137               'First argument to File_function must be a string'
     
    148148
    149149    if domain is not None:
    150         quantities = domain.conserved_quantities
     150        quantities = domain.conserved_quantities   
    151151    else:
    152152        quantities = None
    153 
    154     #Choose format
     153       
     154    #Choose format 
    155155    #FIXME: Maybe these can be merged later on
    156156    if line[:3] == 'CDF':
    157157        return File_function_NetCDF(filename, domain, quantities, interpolation_points, verbose = verbose)
    158158    else:
    159         return File_function_ASCII(filename, domain, quantities, interpolation_points)
    160 
    161 
     159        return File_function_ASCII(filename, domain, quantities, interpolation_points)   
     160           
     161             
    162162class File_function_NetCDF:
    163     """Read time history of spatial data from NetCDF sww file and
    164     return a callable object f(t,x,y)
    165     which will return interpolated values based on the input file.
    166 
     163    """Read time history of spatial data from NetCDF sww file and 
     164    return a callable object f(t,x,y) 
     165    which will return interpolated values based on the input file.   
     166   
    167167    x, y may be either scalars or vectors
    168 
     168   
    169169    #FIXME: More about format, interpolation  and order of quantities
    170 
     170   
    171171    The quantities returned by the callable objects are specified by
    172     the list quantities which must contain the names of the
     172    the list quantities which must contain the names of the 
    173173    quantities to be returned and also reflect the order, e.g. for
    174     the shallow water wave equation, on would have
     174    the shallow water wave equation, on would have 
    175175    quantities = ['stage', 'xmomentum', 'ymomentum']
    176 
    177     interpolation_points decides at which points interpolated
     176   
     177    interpolation_points decides at which points interpolated 
    178178    quantities are to be computed whenever object is called.
    179 
    180 
    181 
     179   
     180   
     181   
    182182    If None, return average value
    183183    """
    184 
     184   
    185185    def  __init__(self, filename, domain=None, quantities=None,
    186186                  interpolation_points=None, verbose = False):
     
    189189        If domain is specified, model time (domain.starttime)
    190190        will be checked and possibly modified
    191 
     191       
    192192        All times are assumed to be in UTC
    193193        """
     
    196196        #(both in UTM coordinates)
    197197        #If not - modify those from file to match domain
    198 
     198       
    199199        import time, calendar
    200200        from config import time_format
    201         from Scientific.IO.NetCDF import NetCDFFile
     201        from Scientific.IO.NetCDF import NetCDFFile     
    202202
    203203        #Open NetCDF file
     
    213213             if not fid.variables.has_key(quantity):
    214214                 missing.append(quantity)
    215 
     215                 
    216216        if len(missing) > 0:
    217217            msg = 'Quantities %s could not be found in file %s'\
    218218                  %(str(missing), filename)
    219219            raise msg
    220 
     220                 
    221221
    222222        #Get first timestep
    223223        try:
    224224            self.starttime = fid.starttime[0]
    225         except ValueError:
     225        except ValueError:   
    226226            msg = 'Could not read starttime from file %s' %filename
    227227            raise msg
     
    229229        #Get origin
    230230        self.xllcorner = fid.xllcorner[0]
    231         self.yllcorner = fid.yllcorner[0]
    232 
     231        self.yllcorner = fid.yllcorner[0]           
     232   
    233233        self.number_of_values = len(quantities)
    234234        self.fid = fid
    235235        self.filename = filename
    236         self.quantities = quantities
    237         self.domain = domain
    238         self.interpolation_points = interpolation_points
     236        self.quantities = quantities
     237        self.domain = domain
     238        self.interpolation_points = interpolation_points
    239239
    240240        if domain is not None:
     
    249249                if verbose: print 'Domain starttime is now set to %f' %domain.starttime
    250250
    251         #Read all data in and produce values for desired data points at each timestep
    252         self.spatial_interpolation(interpolation_points, verbose = verbose)
     251        #Read all data in and produce values for desired data points at each timestep
     252        self.spatial_interpolation(interpolation_points, verbose = verbose) 
    253253        fid.close()
    254254
    255255    def spatial_interpolation(self, interpolation_points, verbose = False):
    256         """For each timestep in fid: read surface, interpolate to desired points
    257            and store values for use when object is called.
     256        """For each timestep in fid: read surface, interpolate to desired points 
     257        and store values for use when object is called.
    258258        """
    259 
     259       
    260260        from Numeric import array, zeros, Float, alltrue, concatenate, reshape
    261261
    262262        from config import time_format
    263         from least_squares import Interpolation
     263        from least_squares import Interpolation
    264264        import time, calendar
    265 
     265       
    266266        fid = self.fid
    267267
     
    273273        triangles = fid.variables['volumes'][:]
    274274        time = fid.variables['time'][:]
    275 
    276         #Check
     275       
     276        #Check
    277277        msg = 'File %s must list time as a monotonuosly ' %self.filename
    278278        msg += 'increasing sequence'
    279         assert alltrue(time[1:] - time[:-1] > 0 ), msg
    280 
    281 
    282         if interpolation_points is not None:
    283 
     279        assert alltrue(time[1:] - time[:-1] > 0 ), msg 
     280       
     281
     282        if interpolation_points is not None: 
     283       
    284284            try:
    285                 P = ensure_numeric(interpolation_points)
     285                P = ensure_numeric(interpolation_points) 
    286286            except:
    287287                msg = 'Interpolation points must be an N x 2 Numeric array or a list of points\n'
    288288                msg += 'I got: %s.' %( str(interpolation_points)[:60] + '...')
    289289                raise msg
    290 
    291 
     290           
     291           
    292292            self.T = time[:]  #Time assumed to be relative to starttime
    293             self.index = 0    #Initial time index
    294 
    295             self.values = {}
     293            self.index = 0    #Initial time index       
     294
     295            self.values = {}               
    296296            for name in self.quantities:
    297                 self.values[name] = zeros( (len(self.T),
    298                                             len(interpolation_points)),
    299                                             Float)
     297                self.values[name] = zeros( (len(self.T), 
     298                                            len(interpolation_points)), 
     299                                            Float)                 
    300300
    301301            #Build interpolator
    302302            if verbose: print 'Build interpolation matrix'
    303303            x = reshape(x, (len(x),1))
    304             y = reshape(y, (len(y),1))
     304            y = reshape(y, (len(y),1))               
    305305            vertex_coordinates = concatenate((x,y), axis=1) #m x 2 array
    306306
    307             interpol = Interpolation(vertex_coordinates,
     307            interpol = Interpolation(vertex_coordinates, 
    308308                                     triangles,
    309309                                     point_coordinates = P,
    310                                      alpha = 0,
     310                                     alpha = 0, 
    311311                                     verbose = verbose)
    312312
    313313
    314314            if verbose: print 'Interpolate'
    315             for i, t in enumerate(self.T):
     315            for i, t in enumerate(self.T):
    316316                #Interpolate quantities at this timestep
    317317                #print ' time step %d of %d' %(i, len(self.T))
    318318                for name in self.quantities:
    319                     self.values[name][i, :] =\
    320                                    interpol.interpolate(fid.variables[name][i,:])
     319                    self.values[name][i, :] =\
     320                    interpol.interpolate(fid.variables[name][i,:])   
    321321
    322322            #Report
     
    327327                print '  Reference:'
    328328                print '    Lower left corner: [%f, %f]'\
    329                       %(self.xllcorner, self.yllcorner)
     329                      %(self.xllcorner, self.yllcorner) 
    330330                print '    Start time (file):   %f' %self.starttime
    331331                #print '    Start time (domain): %f' %domain.starttime
     
    342342                    print '    %s in [%f, %f]' %(name, min(q), max(q))
    343343
    344 
     344                   
    345345                print '  Interpolation points (xi, eta):'\
    346346                      'number of points == %d ' %P.shape[0]
     
    349349                print '  Interpolated quantities (over all timesteps):'
    350350                for name in self.quantities:
    351                     q = self.values[name][:].flat
     351                    q = self.values[name][:].flat                   
    352352                    print '    %s at interpolation points in [%f, %f]'\
    353                           %(name, min(q), max(q))
     353                          %(name, min(q), max(q))               
     354               
     355               
     356               
    354357
    355358                print '------------------------------------------------'
     
    364367    def __call__(self, t, x=None, y=None, point_id = None):
    365368        """Evaluate f(t, point_id)
    366 
    367            Inputs:
    368            t: time - Model time (tau = domain.starttime-self.starttime+t)
    369                      must lie within existing timesteps
    370            point_id: index of one of the preprocessed points.
    371                   If point_id is None all preprocessed points are computed
    372 
    373            FIXME: point_id could also be a slice
    374            FIXME: One could allow arbitrary x, y coordinates
    375            (requires computation of a new interpolator)
    376            Maybe not,.,.
    377            FIXME: What if x and y are vectors?
     369       
     370        Inputs:
     371          t: time - Model time (tau = domain.starttime-self.starttime+t) 
     372                    must lie within existing timesteps   
     373          point_id: index of one of the preprocessed points.
     374                    If point_id is None all preprocessed points are computed
     375
     376          FIXME: point_id could also be a slice     
     377          FIXME: One could allow arbitrary x, y coordinates
     378          (requires computation of a new interpolator)
     379          Maybe not,.,.
     380          FIXME: What if x and y are vectors?
    378381        """
    379382
     
    388391
    389392        #Find time tau such that
    390         #
    391         # domain.starttime + t == self.starttime + tau
    392 
    393         if self.domain is not None:
     393        #
     394        # domain.starttime + t == self.starttime + tau
     395       
     396        if self.domain is not None:
    394397            tau = self.domain.starttime-self.starttime+t
    395         else:
     398        else:
    396399            #print 'DOMAIN IS NONE!!!!!!!!!'
    397400            tau = t
     
    400403        #print 'S start', self.starttime
    401404        #print 't', t
    402         #print 'tau', tau
    403 
     405        #print 'tau', tau             
     406               
    404407        msg = 'Time interval derived from file %s [%s:%s]'\
    405408              %(self.filename, self.T[0], self.T[1])
     
    408411
    409412        if tau < self.T[0]: raise msg
    410         if tau > self.T[-1]: raise msg
     413        if tau > self.T[-1]: raise msg       
    411414
    412415
     
    421424            #Protect against case where tau == T[-1] (last time)
    422425            # - also works in general when tau == T[i]
    423             ratio = 0
     426            ratio = 0 
    424427        else:
    425             #t is now between index and index+1
     428            #t is now between index and index+1           
    426429            ratio = (tau - self.T[self.index])/\
    427430                    (self.T[self.index+1] - self.T[self.index])
     
    429432
    430433
    431 
     434               
    432435        #Compute interpolated values
    433436        q = zeros( len(self.quantities), Float)
    434437
    435438        for i, name in enumerate(self.quantities):
    436             Q = self.values[name]
     439            Q = self.values[name]   
    437440
    438441            if ratio > 0:
     
    447450        #Return vector of interpolated values
    448451        return q
    449 
    450 
     452               
     453             
    451454class File_function_ASCII:
    452455    """Read time series from file and return a callable object:
    453        f(t,x,y)
    454        which will return interpolated values based on the input file.
    455 
    456        The file format is assumed to be either two fields separated by a comma:
    457 
    458        time [DD/MM/YY hh:mm:ss], value0 value1 value2 ...
    459 
    460        or four comma separated fields
    461 
    462        time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ...
    463 
    464        In either case, the callable object will return a tuple of
    465        interpolated values, one each value stated in the file.
    466 
    467 
    468        E.g
    469 
    470        31/08/04 00:00:00, 1.328223 0 0
    471        31/08/04 00:15:00, 1.292912 0 0
    472 
    473        will provide a time dependent function f(t,x=None,y=None),
    474        ignoring x and y, which returns three values per call.
    475 
    476 
    477        NOTE: At this stage the function is assumed to depend on
    478        time only, i.e  no spatial dependency!!!!!
    479        When that is needed we can use the least_squares interpolation.
    480 
    481        #FIXME: This should work with netcdf (e.g. sww) and thus render the
    482        #spatio-temporal boundary condition in shallow water fully general
    483 
    484        #FIXME: Specified quantites not used here -
    485        #always return whatever is in the file
    486     """
    487 
    488 
     456    f(t,x,y)
     457    which will return interpolated values based on the input file.
     458
     459    The file format is assumed to be either two fields separated by a comma:
     460
     461        time [DD/MM/YY hh:mm:ss], value0 value1 value2 ...
     462
     463    or four comma separated fields
     464
     465        time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ...
     466
     467    In either case, the callable object will return a tuple of
     468    interpolated values, one each value stated in the file.
     469
     470   
     471    E.g
     472
     473      31/08/04 00:00:00, 1.328223 0 0
     474      31/08/04 00:15:00, 1.292912 0 0
     475
     476    will provide a time dependent function f(t,x=None,y=None),
     477    ignoring x and y, which returns three values per call.
     478
     479   
     480    NOTE: At this stage the function is assumed to depend on
     481    time only, i.e  no spatial dependency!!!!!
     482    When that is needed we can use the least_squares interpolation.
     483   
     484    #FIXME: This should work with netcdf (e.g. sww) and thus render the
     485    #spatio-temporal boundary condition in shallow water fully general
     486   
     487    #FIXME: Specified quantites not used here -
     488    #always return whatever is in the file
     489    """
     490
     491   
    489492    def __init__(self, filename, domain=None, quantities = None, interpolation_points=None):
    490493        """Initialise callable object from a file.
     
    504507        line = fid.readline()
    505508        fid.close()
    506 
     509   
    507510        fields = line.split(',')
    508511        msg = 'File %s must have the format date, value0 value1 value2 ...'
     
    513516        try:
    514517            starttime = calendar.timegm(time.strptime(fields[0], time_format))
    515         except ValueError:
     518        except ValueError:   
    516519            msg = 'First field in file %s must be' %filename
    517520            msg += ' date-time with format %s.\n' %time_format
    518             msg += 'I got %s instead.' %fields[0]
     521            msg += 'I got %s instead.' %fields[0] 
    519522            raise msg
    520523
     
    526529
    527530        q = ensure_numeric(values)
    528 
     531       
    529532        msg = 'ERROR: File must contain at least one independent value'
    530533        assert len(q.shape) == 1, msg
    531 
     534           
    532535        self.number_of_values = len(q)
    533536
    534537        self.filename = filename
    535538        self.starttime = starttime
    536         self.domain = domain
     539        self.domain = domain
    537540
    538541        if domain is not None:
     
    546549                ##if verbose: print msg
    547550                domain.starttime = self.starttime #Modifying model time
    548 
     551       
    549552            #if domain.starttime is None:
    550553            #    domain.starttime = self.starttime
     
    560563            #        domain.starttime = self.starttime #Modifying model time
    561564
    562         if mode == 2:
     565        if mode == 2:       
    563566            self.read_times() #Now read all times in.
    564567        else:
    565568            raise 'x,y dependency not yet implemented'
    566569
    567 
     570       
    568571    def read_times(self):
    569         """Read time and values
     572        """Read time and values 
    570573        """
    571574        from Numeric import zeros, Float, alltrue
    572575        from config import time_format
    573576        import time, calendar
    574 
    575         fid = open(self.filename)
     577       
     578        fid = open(self.filename)       
    576579        lines = fid.readlines()
    577580        fid.close()
    578 
     581       
    579582        N = len(lines)
    580583        d = self.number_of_values
     
    582585        T = zeros(N, Float)       #Time
    583586        Q = zeros((N, d), Float)  #Values
    584 
     587       
    585588        for i, line in enumerate(lines):
    586589            fields = line.split(',')
     
    600603        self.index = 0 #Initial index
    601604
    602 
     605       
    603606    def __repr__(self):
    604607        return 'File function'
     
    610613        result is a vector of same length as x and y
    611614        FIXME: Naaaa
    612 
    613         FIXME: Rethink semantics when x,y are vectors.
     615       
     616        FIXME: Rethink semantics when x,y are vectors.
    614617        """
    615618
    616619        from math import pi, cos, sin, sqrt
    617 
     620       
    618621
    619622        #Find time tau such that
    620         #
    621         # domain.starttime + t == self.starttime + tau
    622 
    623         if self.domain is not None:
     623        #
     624        # domain.starttime + t == self.starttime + tau
     625       
     626        if self.domain is not None:
    624627            tau = self.domain.starttime-self.starttime+t
    625         else:
     628        else:
    626629            tau = t
    627 
    628 
     630       
     631               
    629632        msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\
    630633              %(self.filename, self.T[0], self.T[1], tau)
    631634        if tau < self.T[0]: raise msg
    632         if tau > self.T[-1]: raise msg
     635        if tau > self.T[-1]: raise msg       
    633636
    634637        oldindex = self.index
     
    644647        #Compute interpolated values
    645648        q = self.Q[self.index,:] +\
    646             ratio*(self.Q[self.index+1,:] - self.Q[self.index,:])
     649            ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 
    647650
    648651        #Return vector of interpolated values
     
    659662                N = len(x)
    660663                assert len(y) == N, 'x and y must have same length'
    661 
     664             
    662665                res = []
    663666                for col in q:
    664667                    res.append(col*ones(N, Float))
    665 
     668           
    666669                return res
    667 
    668 
    669 #FIXME: TEMP
     670           
     671           
     672#FIXME: TEMP       
    670673class File_function_copy:
    671674    """Read time series from file and return a callable object:
    672        f(t,x,y)
    673        which will return interpolated values based on the input file.
    674 
    675        The file format is assumed to be either two fields separated by a comma:
    676 
    677            time [DD/MM/YY hh:mm:ss], value0 value1 value2 ...
    678 
    679        or four comma separated fields
    680 
    681            time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ...
    682 
    683        In either case, the callable object will return a tuple of
    684        interpolated values, one each value stated in the file.
    685 
    686 
    687        E.g
    688 
    689          31/08/04 00:00:00, 1.328223 0 0
    690          31/08/04 00:15:00, 1.292912 0 0
    691 
    692        will provide a time dependent function f(t,x=None,y=None),
    693        ignoring x and y, which returns three values per call.
    694 
    695 
    696        NOTE: At this stage the function is assumed to depend on
    697        time only, i.e  no spatial dependency!!!!!
    698        When that is needed we can use the least_squares interpolation.
    699 
    700        #FIXME: This should work with netcdf (e.g. sww) and thus render the
    701        #spatio-temporal boundary condition in shallow water fully general
    702     """
    703 
    704 
     675    f(t,x,y)
     676    which will return interpolated values based on the input file.
     677
     678    The file format is assumed to be either two fields separated by a comma:
     679
     680        time [DD/MM/YY hh:mm:ss], value0 value1 value2 ...
     681
     682    or four comma separated fields
     683
     684        time [DD/MM/YY hh:mm:ss], x, y, value0 value1 value2 ...
     685
     686    In either case, the callable object will return a tuple of
     687    interpolated values, one each value stated in the file.
     688
     689   
     690    E.g
     691
     692      31/08/04 00:00:00, 1.328223 0 0
     693      31/08/04 00:15:00, 1.292912 0 0
     694
     695    will provide a time dependent function f(t,x=None,y=None),
     696    ignoring x and y, which returns three values per call.
     697
     698   
     699    NOTE: At this stage the function is assumed to depend on
     700    time only, i.e  no spatial dependency!!!!!
     701    When that is needed we can use the least_squares interpolation.
     702   
     703    #FIXME: This should work with netcdf (e.g. sww) and thus render the
     704    #spatio-temporal boundary condition in shallow water fully general
     705    """
     706
     707   
    705708    def __init__(self, filename, domain=None):
    706709        """Initialise callable object from a file.
     
    739742        try:
    740743            starttime = calendar.timegm(time.strptime(fields[0], time_format))
    741         except ValueError:
     744        except ValueError:   
    742745            msg = 'First field in file %s must be' %filename
    743746            msg += ' date-time with format %s.\n' %time_format
    744             msg += 'I got %s instead.' %fields[0]
     747            msg += 'I got %s instead.' %fields[0] 
    745748            raise msg
    746749
     
    752755
    753756        q = ensure_numeric(values)
    754 
     757       
    755758        msg = 'ERROR: File must contain at least one independent value'
    756759        assert len(q.shape) == 1, msg
    757 
     760           
    758761        self.number_of_values = len(q)
    759762
    760763        self.filename = filename
    761764        self.starttime = starttime
    762         self.domain = domain
     765        self.domain = domain
    763766
    764767        if domain is not None:
     
    776779                    domain.starttime = self.starttime #Modifying model time
    777780
    778         if mode == 2:
     781        if mode == 2:       
    779782            self.read_times() #Now read all times in.
    780783        else:
    781784            raise 'x,y dependency not yet implemented'
    782785
    783 
     786       
    784787    def read_times(self):
    785         """Read time and values
     788        """Read time and values 
    786789        """
    787790        from Numeric import zeros, Float, alltrue
    788791        from config import time_format
    789792        import time, calendar
    790 
    791         fid = open(self.filename)
     793       
     794        fid = open(self.filename)       
    792795        lines = fid.readlines()
    793796        fid.close()
    794 
     797       
    795798        N = len(lines)
    796799        d = self.number_of_values
     
    798801        T = zeros(N, Float)       #Time
    799802        Q = zeros((N, d), Float)  #Values
    800 
     803       
    801804        for i, line in enumerate(lines):
    802805            fields = line.split(',')
     
    816819        self.index = 0 #Initial index
    817820
    818 
     821       
    819822    def __repr__(self):
    820823        return 'File function'
    821824
    822 
     825       
    823826
    824827    def __call__(self, t, x=None, y=None):
     
    831834
    832835        from math import pi, cos, sin, sqrt
    833 
     836       
    834837
    835838        #Find time tau such that
    836         #
    837         # domain.starttime + t == self.starttime + tau
    838 
    839         if self.domain is not None:
     839        #
     840        # domain.starttime + t == self.starttime + tau
     841       
     842        if self.domain is not None:
    840843            tau = self.domain.starttime-self.starttime+t
    841         else:
     844        else:
    842845            tau = t
    843 
    844 
     846       
     847               
    845848        msg = 'Time interval derived from file %s (%s:%s) does not match model time: %s'\
    846849              %(self.filename, self.T[0], self.T[1], tau)
    847850        if tau < self.T[0]: raise msg
    848         if tau > self.T[-1]: raise msg
     851        if tau > self.T[-1]: raise msg       
    849852
    850853        oldindex = self.index
     
    860863        #Compute interpolated values
    861864        q = self.Q[self.index,:] +\
    862             ratio*(self.Q[self.index+1,:] - self.Q[self.index,:])
     865            ratio*(self.Q[self.index+1,:] - self.Q[self.index,:]) 
    863866
    864867        #Return vector of interpolated values
     
    875878                N = len(x)
    876879                assert len(y) == N, 'x and y must have same length'
    877 
     880             
    878881                res = []
    879882                for col in q:
    880883                    res.append(col*ones(N, Float))
    881 
     884           
    882885                return res
    883 
     886           
    884887
    885888def read_xya(filename, format = 'netcdf'):
     
    889892
    890893    Format can be either ASCII or NetCDF
    891 
     894   
    892895    Return list of points, list of attributes and
    893896    attribute names if present otherwise None
    894897    """
    895898    #FIXME: Probably obsoleted by similar function in load_ASCII
    896 
     899   
    897900    from Scientific.IO.NetCDF import NetCDFFile
    898901
    899     if format.lower() == 'netcdf':
     902    if format.lower() == 'netcdf': 
    900903        #Get NetCDF
    901 
    902         fid = NetCDFFile(filename, 'r')
    903 
     904       
     905        fid = NetCDFFile(filename, 'r') 
     906     
    904907        # Get the variables
    905908        points = fid.variables['points']
     
    910913        #Don't close - arrays are needed outside this function,
    911914        #alternatively take a copy here
    912     else:
     915    else:   
    913916        #Read as ASCII file assuming that it is separated by whitespace
    914917        fid = open(filename)
     
    927930            attribute_names = ['elevation']  #HACK
    928931
    929         attributes = {}
     932        attributes = {}   
    930933        for key in attribute_names:
    931934            attributes[key] = []
     
    937940            for i, key in enumerate(attribute_names):
    938941                attributes[key].append( float(fields[2+i]) )
    939 
     942       
    940943    return points, attributes
    941 
     944   
    942945
    943946#####################################
     
    947950
    948951
    949 
    950 #Redefine these to use separate_by_polygon which will put all inside indices
     952             
     953#Redefine these to use separate_by_polygon which will put all inside indices 
    951954#in the first part of the indices array and outside indices in the last
    952955
     
    954957    """See separate_points_by_polygon for documentation
    955958    """
    956 
    957     from Numeric import array, Float, reshape
    958 
    959     if verbose: print 'Checking input to inside_polygon'
     959   
     960    from Numeric import array, Float, reshape   
     961   
     962    if verbose: print 'Checking input to inside_polygon'   
    960963    try:
    961         points = ensure_numeric(points, Float)
     964        points = ensure_numeric(points, Float)             
    962965    except:
    963966        msg = 'Points could not be converted to Numeric array'
    964         raise msg
    965 
     967        raise msg       
     968       
    966969    try:
    967         polygon = ensure_numeric(polygon, Float)
     970        polygon = ensure_numeric(polygon, Float)           
    968971    except:
    969972        msg = 'Polygon could not be converted to Numeric array'
    970         raise msg
    971 
    972 
    973 
     973        raise msg               
     974   
     975   
     976   
    974977    if len(points.shape) == 1:
    975978        one_point = True
    976979        points = reshape(points, (1,2))
    977     else:
     980    else:       
    978981        one_point = False
    979982
    980     indices, count = separate_points_by_polygon(points, polygon,
    981                                                 closed, verbose)
    982 
     983    indices, count = separate_points_by_polygon(points, polygon, 
     984                                                closed, verbose)     
     985   
    983986    if one_point:
    984987        return count == 1
    985988    else:
    986         return indices[:count]
    987 
     989        return indices[:count]   
     990       
    988991def outside_polygon(points, polygon, closed = True, verbose = False):
    989992    """See separate_points_by_polygon for documentation
    990993    """
    991 
    992     from Numeric import array, Float, reshape
    993 
    994     if verbose: print 'Checking input to outside_polygon'
     994   
     995    from Numeric import array, Float, reshape   
     996   
     997    if verbose: print 'Checking input to outside_polygon'   
    995998    try:
    996         points = ensure_numeric(points, Float)
     999        points = ensure_numeric(points, Float)             
    9971000    except:
    9981001        msg = 'Points could not be converted to Numeric array'
    999         raise msg
    1000 
     1002        raise msg       
     1003       
    10011004    try:
    1002         polygon = ensure_numeric(polygon, Float)
     1005        polygon = ensure_numeric(polygon, Float)           
    10031006    except:
    10041007        msg = 'Polygon could not be converted to Numeric array'
    1005         raise msg
    1006 
    1007 
    1008 
     1008        raise msg               
     1009   
     1010   
     1011   
    10091012    if len(points.shape) == 1:
    10101013        one_point = True
    10111014        points = reshape(points, (1,2))
    1012     else:
     1015    else:       
    10131016        one_point = False
    10141017
    1015     indices, count = separate_points_by_polygon(points, polygon,
    1016                                                 closed, verbose)
    1017 
     1018    indices, count = separate_points_by_polygon(points, polygon, 
     1019                                                closed, verbose)     
     1020   
    10181021    if one_point:
    10191022        return count != 1
    10201023    else:
    1021         return indices[count:][::-1]  #return reversed
    1022 
    1023 
    1024 def separate_points_by_polygon(points, polygon,
     1024        return indices[count:][::-1]  #return reversed   
     1025       
     1026
     1027def separate_points_by_polygon(points, polygon, 
    10251028                               closed = True, verbose = False):
    10261029    """Determine whether points are inside or outside a polygon
    1027 
     1030   
    10281031    Input:
    10291032       points - Tuple of (x, y) coordinates, or list of tuples
    10301033       polygon - list of vertices of polygon
    1031        closed - (optional) determine whether points on boundary should be
    1032        regarded as belonging to the polygon (closed = True)
    1033        or not (closed = False)
    1034 
     1034       closed - (optional) determine whether points on boundary should be 
     1035       regarded as belonging to the polygon (closed = True) 
     1036       or not (closed = False) 
     1037   
    10351038    Outputs:
    1036        indices: array of same length as points with indices of points falling
    1037        inside the polygon listed from the beginning and indices of points
     1039       indices: array of same length as points with indices of points falling 
     1040       inside the polygon listed from the beginning and indices of points 
    10381041       falling outside listed from the end.
    1039 
     1042       
    10401043       count: count of points falling inside the polygon
    1041 
     1044       
    10421045       The indices of points inside are obtained as indices[:count]
    1043        The indices of points outside are obtained as indices[count:]
    1044 
    1045 
     1046       The indices of points outside are obtained as indices[count:]       
     1047       
     1048       
    10461049    Examples:
    10471050       U = [[0,0], [1,0], [1,1], [0,1]] #Unit square
    1048 
     1051       
    10491052       separate_points_by_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U)
    1050        will return the indices [0, 2, 1] and count == 2 as only the first
     1053       will return the indices [0, 2, 1] and count == 2 as only the first 
    10511054       and the last point are inside the unit square
    1052 
     1055       
    10531056    Remarks:
    10541057       The vertices may be listed clockwise or counterclockwise and
    1055        the first point may optionally be repeated.
     1058       the first point may optionally be repeated.   
    10561059       Polygons do not need to be convex.
    1057        Polygons can have holes in them and points inside a hole is
    1058        regarded as being outside the polygon.
    1059 
    1060     Algorithm is based on work by Darel Finley,
    1061     http://www.alienryderflex.com/polygon/
    1062 
    1063     """
     1060       Polygons can have holes in them and points inside a hole is 
     1061       regarded as being outside the polygon.         
     1062               
     1063    Algorithm is based on work by Darel Finley, 
     1064    http://www.alienryderflex.com/polygon/ 
     1065   
     1066    """   
    10641067
    10651068    from Numeric import array, Float, reshape, Int, zeros
    1066 
    1067 
     1069   
     1070   
     1071    #Input checks
     1072    try:
     1073        points = ensure_numeric(points, Float)             
     1074    except:
     1075        msg = 'Points could not be converted to Numeric array'
     1076        raise msg       
     1077       
     1078    try:
     1079        polygon = ensure_numeric(polygon, Float)           
     1080    except:
     1081        msg = 'Polygon could not be converted to Numeric array'
     1082        raise msg               
     1083
     1084    assert len(polygon.shape) == 2,\
     1085       'Polygon array must be a 2d array of vertices'
     1086
     1087    assert polygon.shape[1] == 2,\
     1088       'Polygon array must have two columns'
     1089
     1090    assert len(points.shape) == 2,\
     1091       'Points array must be a 2d array'
     1092       
     1093    assert points.shape[1] == 2,\
     1094       'Points array must have two columns'
     1095       
     1096    N = polygon.shape[0] #Number of vertices in polygon
     1097    M = points.shape[0]  #Number of points
     1098   
     1099    px = polygon[:,0]
     1100    py = polygon[:,1]   
     1101
     1102    #Used for an optimisation when points are far away from polygon
     1103    minpx = min(px); maxpx = max(px)
     1104    minpy = min(py); maxpy = max(py)   
     1105
     1106
     1107    #Begin main loop
     1108    indices = zeros(M, Int)
     1109   
     1110    inside_index = 0    #Keep track of points inside
     1111    outside_index = M-1 #Keep track of points outside (starting from end)
     1112   
     1113    for k in range(M):
     1114
     1115        if verbose:
     1116            if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M)
     1117       
     1118        #for each point   
     1119        x = points[k, 0]
     1120        y = points[k, 1]       
     1121
     1122        inside = False
     1123
     1124        if not x > maxpx or x < minpx or y > maxpy or y < minpy:
     1125            #Check polygon
     1126            for i in range(N):
     1127                j = (i+1)%N
     1128               
     1129                #Check for case where point is contained in line segment       
     1130                if point_on_line(x, y, px[i], py[i], px[j], py[j]):
     1131                    if closed:
     1132                        inside = True
     1133                    else:       
     1134                        inside = False
     1135                    break
     1136                else:   
     1137                    #Check if truly inside polygon                 
     1138                    if py[i] < y and py[j] >= y or\
     1139                       py[j] < y and py[i] >= y:
     1140                        if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x:
     1141                            inside = not inside
     1142       
     1143        if inside:
     1144            indices[inside_index] = k
     1145            inside_index += 1
     1146        else:
     1147            indices[outside_index] = k
     1148            outside_index -= 1   
     1149           
     1150    return indices, inside_index
     1151
     1152
     1153def separate_points_by_polygon_c(points, polygon,
     1154                                 closed = True, verbose = False):
     1155    """Determine whether points are inside or outside a polygon
     1156
     1157    C-wrapper
     1158    """   
     1159
     1160    from Numeric import array, Float, reshape, zeros, Int
     1161   
     1162
     1163    if verbose: print 'Checking input to separate_points_by_polygon'   
    10681164    #Input checks
    10691165    try:
     
    10731169        raise msg
    10741170
     1171    #if verbose: print 'Checking input to separate_points_by_polygon 2'
    10751172    try:
    10761173        polygon = ensure_numeric(polygon, Float)
    10771174    except:
    10781175        msg = 'Polygon could not be converted to Numeric array'
    1079         raise msg
    1080 
     1176        raise msg               
     1177
     1178    if verbose: print 'check'
     1179   
    10811180    assert len(polygon.shape) == 2,\
    10821181       'Polygon array must be a 2d array of vertices'
     
    10871186    assert len(points.shape) == 2,\
    10881187       'Points array must be a 2d array'
    1089 
     1188       
    10901189    assert points.shape[1] == 2,\
    10911190       'Points array must have two columns'
    1092 
    1093     N = polygon.shape[0] #Number of vertices in polygon
     1191       
     1192    N = polygon.shape[0] #Number of vertices in polygon 
    10941193    M = points.shape[0]  #Number of points
    10951194
    1096     px = polygon[:,0]
    1097     py = polygon[:,1]
    1098 
    1099     #Used for an optimisation when points are far away from polygon
    1100     minpx = min(px); maxpx = max(px)
    1101     minpy = min(py); maxpy = max(py)
    1102 
    1103 
    1104     #Begin main loop
    1105     indices = zeros(M, Int)
    1106 
    1107     inside_index = 0    #Keep track of points inside
    1108     outside_index = M-1 #Keep track of points outside (starting from end)
    1109 
    1110     for k in range(M):
    1111 
    1112         if verbose:
    1113             if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M)
    1114 
    1115         #for each point
    1116         x = points[k, 0]
    1117         y = points[k, 1]
    1118 
    1119         inside = False
    1120 
    1121         if not x > maxpx or x < minpx or y > maxpy or y < minpy:
    1122             #Check polygon
    1123             for i in range(N):
    1124                 j = (i+1)%N
    1125 
    1126                 #Check for case where point is contained in line segment
    1127                 if point_on_line(x, y, px[i], py[i], px[j], py[j]):
    1128                     if closed:
    1129                         inside = True
    1130                     else:
    1131                         inside = False
    1132                     break
    1133                 else:
    1134                     #Check if truly inside polygon
    1135                     if py[i] < y and py[j] >= y or\
    1136                        py[j] < y and py[i] >= y:
    1137                         if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x:
    1138                             inside = not inside
    1139 
    1140         if inside:
    1141             indices[inside_index] = k
    1142             inside_index += 1
    1143         else:
    1144             indices[outside_index] = k
    1145             outside_index -= 1
    1146 
    1147     return indices, inside_index
    1148 
    1149 
    1150 def separate_points_by_polygon_c(points, polygon,
    1151                                  closed = True, verbose = False):
    1152     """Determine whether points are inside or outside a polygon
    1153 
    1154     C-wrapper
    1155     """
    1156 
    1157     from Numeric import array, Float, reshape, zeros, Int
    1158 
    1159 
    1160     if verbose: print 'Checking input to separate_points_by_polygon'
    1161     #Input checks
    1162     try:
    1163         points = ensure_numeric(points, Float)
    1164     except:
    1165         msg = 'Points could not be converted to Numeric array'
    1166         raise msg
    1167 
    1168     #if verbose: print 'Checking input to separate_points_by_polygon 2'
    1169     try:
    1170         polygon = ensure_numeric(polygon, Float)
    1171     except:
    1172         msg = 'Polygon could not be converted to Numeric array'
    1173         raise msg
    1174 
    1175     if verbose: print 'check'
    1176 
    1177     assert len(polygon.shape) == 2,\
    1178        'Polygon array must be a 2d array of vertices'
    1179 
    1180     assert polygon.shape[1] == 2,\
    1181        'Polygon array must have two columns'
    1182 
    1183     assert len(points.shape) == 2,\
    1184        'Points array must be a 2d array'
    1185 
    1186     assert points.shape[1] == 2,\
    1187        'Points array must have two columns'
    1188 
    1189     N = polygon.shape[0] #Number of vertices in polygon
    1190     M = points.shape[0]  #Number of points
    1191 
    11921195    from util_ext import separate_points_by_polygon
    11931196
     
    11961199    indices = zeros( M, Int )
    11971200
    1198     if verbose: print 'Calling C-version of inside poly'
     1201    if verbose: print 'Calling C-version of inside poly' 
    11991202    count = separate_points_by_polygon(points, polygon, indices,
    12001203                                       int(closed), int(verbose))
    12011204
    1202     return indices, count
     1205    return indices, count 
    12031206
    12041207
    12051208
    12061209class Polygon_function:
    1207     """Create callable object f: x,y -> z, where a,y,z are vectors and
    1208     where f will return different values depending on whether x,y belongs
     1210    """Create callable object f: x,y -> z, where a,y,z are vectors and 
     1211    where f will return different values depending on whether x,y belongs 
    12091212    to specified polygons.
    1210 
     1213   
    12111214    To instantiate:
    1212 
     1215     
    12131216       Polygon_function(polygons)
    1214 
     1217       
    12151218    where polygons is a list of tuples of the form
    1216 
     1219   
    12171220      [ (P0, v0), (P1, v1), ...]
    1218 
    1219       with Pi being lists of vertices defining polygons and vi either
     1221     
     1222      with Pi being lists of vertices defining polygons and vi either 
    12201223      constants or functions of x,y to be applied to points with the polygon.
    1221 
    1222     The function takes an optional argument, default which is the value
     1224     
     1225    The function takes an optional argument, default which is the value 
    12231226    (or function) to used for points not belonging to any polygon.
    12241227    For example:
    1225 
    1226        Polygon_function(polygons, default = 0.03)
    1227 
    1228     If omitted the default value will be 0.0
    1229 
     1228   
     1229       Polygon_function(polygons, default = 0.03)       
     1230     
     1231    If omitted the default value will be 0.0 
     1232   
    12301233    Note: If two polygons overlap, the one last in the list takes precedence
    12311234
    1232     """
    1233 
     1235    FIXME? : Currently, coordinates specified here are assumed to be relative to the origin (georeference) used by domain. This function is more general than domain so perhaps it'd be an idea to allow the optional argument georeference???
     1236
     1237    """
     1238   
    12341239    def __init__(self, regions, default = 0.0):
    1235 
     1240       
    12361241        try:
    12371242            len(regions)
    12381243        except:
    1239             msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons
     1244            msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons           
    12401245            raise msg
    12411246
    12421247
    1243         T = regions[0]
     1248        T = regions[0]                                   
    12441249        try:
    12451250            a = len(T)
    1246         except:
    1247             msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons
    1248             raise msg
    1249 
    1250         assert a == 2, 'Must have two component each: %s' %T
    1251 
    1252         self.regions = regions
     1251        except:   
     1252            msg = 'Polygon_function takes a list of pairs (polygon, value). Got %s' %polygons           
     1253            raise msg   
     1254                   
     1255        assert a == 2, 'Must have two component each: %s' %T       
     1256
     1257        self.regions = regions             
    12531258        self.default = default
    1254 
    1255 
     1259         
     1260         
    12561261    def __call__(self, x, y):
    12571262        from util import inside_polygon
    12581263        from Numeric import ones, Float, concatenate, array, reshape, choose
    1259 
     1264       
    12601265        x = array(x).astype(Float)
    1261         y = array(y).astype(Float)
    1262 
     1266        y = array(y).astype(Float)     
     1267       
    12631268        N = len(x)
    12641269        assert len(y) == N
    1265 
    1266         points = concatenate( (reshape(x, (N, 1)),
     1270       
     1271        points = concatenate( (reshape(x, (N, 1)), 
    12671272                               reshape(y, (N, 1))), axis=1 )
    12681273
    12691274        if callable(self.default):
    12701275            z = self.default(x,y)
    1271         else:
     1276        else:                   
    12721277            z = ones(N, Float) * self.default
    1273 
     1278           
    12741279        for polygon, value in self.regions:
    12751280            indices = inside_polygon(points, polygon)
    1276 
    1277             #FIXME: This needs to be vectorised
     1281           
     1282            #FIXME: This needs to be vectorised 
    12781283            if callable(value):
    12791284                for i in indices:
     
    12811286                    yy = array([y[i]])
    12821287                    z[i] = value(xx, yy)[0]
    1283             else:
     1288            else:   
    12841289                for i in indices:
    1285                     z[i] = value
    1286 
    1287         return z
     1290                    z[i] = value 
     1291
     1292        return z                 
    12881293
    12891294def read_polygon(filename):
    12901295    """Read points assumed to form a polygon
    12911296       There must be exactly two numbers in each line
    1292     """
    1293 
     1297    """             
     1298   
    12941299    #Get polygon
    12951300    fid = open(filename)
     
    13011306        polygon.append( [float(fields[0]), float(fields[1])] )
    13021307
    1303     return polygon
    1304 
     1308    return polygon     
     1309   
    13051310def populate_polygon(polygon, number_of_points, seed = None):
    13061311    """Populate given polygon with uniformly distributed points.
     
    13081313    Input:
    13091314       polygon - list of vertices of polygon
    1310        number_of_points - (optional) number of points
     1315       number_of_points - (optional) number of points 
    13111316       seed - seed for random number generator (default=None)
    1312 
     1317       
    13131318    Output:
    13141319       points - list of points inside polygon
    1315 
     1320       
    13161321    Examples:
    13171322       populate_polygon( [[0,0], [1,0], [1,1], [0,1]], 5 )
    1318        will return five randomly selected points inside the unit square
     1323       will return five randomly selected points inside the unit square 
    13191324    """
    13201325
     
    13291334    max_y = min_y = polygon[0][1]
    13301335    for point in polygon[1:]:
    1331         x = point[0]
     1336        x = point[0] 
    13321337        if x > max_x: max_x = x
    1333         if x < min_x: min_x = x
    1334         y = point[1]
     1338        if x < min_x: min_x = x           
     1339        y = point[1] 
    13351340        if y > max_y: max_y = y
    1336         if y < min_y: min_y = y
    1337 
    1338 
    1339     while len(points) < number_of_points:
     1341        if y < min_y: min_y = y           
     1342
     1343
     1344    while len(points) < number_of_points:     
    13401345        x = uniform(min_x, max_x)
    1341         y = uniform(min_y, max_y)
     1346        y = uniform(min_y, max_y)       
    13421347
    13431348        if inside_polygon( [x,y], polygon ):
     
    13481353def tsh2sww(filename, verbose=True):
    13491354    """
    1350     to check if a tsh/msh file 'looks' good.
     1355    to check if a tsh/msh file 'looks' good. 
    13511356    """
    13521357    from shallow_water import Domain
    13531358    from pmesh2domain import pmesh_to_domain_instance
    1354     import time, os
    1355     from data_manager import get_dataobject
    1356     from os import sep, path
     1359    import time, os 
     1360    from data_manager import get_dataobject 
     1361    from os import sep, path 
    13571362    #from util import mean
    1358 
     1363   
    13591364    if verbose == True:print 'Creating domain from', filename
    13601365    domain = pmesh_to_domain_instance(filename, Domain)
     
    13731378    if verbose == True:
    13741379        print "Output written to " + domain.get_datadir() + sep + \
    1375               domain.filename + "." + domain.format
     1380              domain.filename + "." + domain.format 
    13761381    sww = get_dataobject(domain)
    13771382    sww.store_connectivity()
     
    13851390    """
    13861391    """
    1387 
    1388     det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0)
     1392   
     1393    det = (y2-y0)*(x1-x0) - (y1-y0)*(x2-x0)           
    13891394    a = (y2-y0)*(q1-q0) - (y1-y0)*(q2-q0)
    13901395    a /= det
    13911396
    13921397    b = (x1-x0)*(q2-q0) - (x2-x0)*(q1-q0)
    1393     b /= det
     1398    b /= det           
    13941399
    13951400    return a, b
     
    14111416    pass
    14121417
    1413 
    1414 
    1415 
    1416 
    1417 
    1418 #OBSOLETED STUFF
     1418   
     1419   
     1420   
     1421   
     1422
     1423#OBSOLETED STUFF   
    14191424def inside_polygon_old(point, polygon, closed = True, verbose = False):
    14201425    #FIXME Obsoleted
    14211426    """Determine whether points are inside or outside a polygon
    1422 
     1427   
    14231428    Input:
    14241429       point - Tuple of (x, y) coordinates, or list of tuples
    14251430       polygon - list of vertices of polygon
    1426        closed - (optional) determine whether points on boundary should be
    1427        regarded as belonging to the polygon (closed = True)
    1428        or not (closed = False)
    1429 
     1431       closed - (optional) determine whether points on boundary should be 
     1432       regarded as belonging to the polygon (closed = True) 
     1433       or not (closed = False) 
     1434   
    14301435    Output:
    14311436       If one point is considered, True or False is returned.
    1432        If multiple points are passed in, the function returns indices
    1433        of those points that fall inside the polygon
    1434 
     1437       If multiple points are passed in, the function returns indices 
     1438       of those points that fall inside the polygon     
     1439       
    14351440    Examples:
    14361441       U = [[0,0], [1,0], [1,1], [0,1]] #Unit square
    14371442       inside_polygon( [0.5, 0.5], U)
    1438        will evaluate to True as the point 0.5, 0.5 is inside the unit square
    1439 
     1443       will evaluate to True as the point 0.5, 0.5 is inside the unit square 
     1444       
    14401445       inside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U)
    1441        will return the indices [0, 2] as only the first and the last point
     1446       will return the indices [0, 2] as only the first and the last point 
    14421447       is inside the unit square
    1443 
     1448       
    14441449    Remarks:
    14451450       The vertices may be listed clockwise or counterclockwise and
    1446        the first point may optionally be repeated.
     1451       the first point may optionally be repeated.   
    14471452       Polygons do not need to be convex.
    1448        Polygons can have holes in them and points inside a hole is
    1449        regarded as being outside the polygon.
    1450 
    1451 
    1452     Algorithm is based on work by Darel Finley,
    1453     http://www.alienryderflex.com/polygon/
    1454 
    1455     """
     1453       Polygons can have holes in them and points inside a hole is 
     1454       regarded as being outside the polygon.         
     1455               
     1456       
     1457    Algorithm is based on work by Darel Finley, 
     1458    http://www.alienryderflex.com/polygon/ 
     1459   
     1460    """   
    14561461
    14571462    from Numeric import array, Float, reshape
    1458 
    1459 
     1463   
     1464   
    14601465    #Input checks
    14611466    try:
    1462         point = array(point).astype(Float)
     1467        point = array(point).astype(Float)         
    14631468    except:
    14641469        msg = 'Point %s could not be converted to Numeric array' %point
    1465         raise msg
    1466 
     1470        raise msg       
     1471       
    14671472    try:
    1468         polygon = array(polygon).astype(Float)
     1473        polygon = array(polygon).astype(Float)             
    14691474    except:
    14701475        msg = 'Polygon %s could not be converted to Numeric array' %polygon
    1471         raise msg
    1472 
     1476        raise msg               
     1477   
    14731478    assert len(polygon.shape) == 2,\
    14741479       'Polygon array must be a 2d array of vertices: %s' %polygon
    14751480
    1476 
     1481       
    14771482    assert polygon.shape[1] == 2,\
    1478        'Polygon array must have two columns: %s' %polygon
     1483       'Polygon array must have two columns: %s' %polygon   
    14791484
    14801485
     
    14821487        one_point = True
    14831488        points = reshape(point, (1,2))
    1484     else:
     1489    else:       
    14851490        one_point = False
    14861491        points = point
    14871492
    1488     N = polygon.shape[0] #Number of vertices in polygon
     1493    N = polygon.shape[0] #Number of vertices in polygon 
    14891494    M = points.shape[0]  #Number of points
    1490 
     1495   
    14911496    px = polygon[:,0]
    1492     py = polygon[:,1]
     1497    py = polygon[:,1]   
    14931498
    14941499    #Used for an optimisation when points are far away from polygon
    14951500    minpx = min(px); maxpx = max(px)
    1496     minpy = min(py); maxpy = max(py)
     1501    minpy = min(py); maxpy = max(py)   
    14971502
    14981503
     
    15031508        if verbose:
    15041509            if k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M)
    1505 
    1506         #for each point
     1510       
     1511        #for each point   
    15071512        x = points[k, 0]
    1508         y = points[k, 1]
     1513        y = points[k, 1]       
    15091514
    15101515        inside = False
     
    15121517        #Optimisation
    15131518        if x > maxpx or x < minpx: continue
    1514         if y > maxpy or y < minpy: continue
    1515 
    1516         #Check polygon
     1519        if y > maxpy or y < minpy: continue       
     1520
     1521        #Check polygon 
    15171522        for i in range(N):
    15181523            j = (i+1)%N
    1519 
    1520             #Check for case where point is contained in line segment
     1524           
     1525            #Check for case where point is contained in line segment   
    15211526            if point_on_line(x, y, px[i], py[i], px[j], py[j]):
    15221527                if closed:
    15231528                    inside = True
    1524                 else:
     1529                else:       
    15251530                    inside = False
    15261531                break
    1527             else:
    1528                 #Check if truly inside polygon
     1532            else:       
     1533                #Check if truly inside polygon             
    15291534                if py[i] < y and py[j] >= y or\
    15301535                   py[j] < y and py[i] >= y:
    15311536                    if px[i] + (y-py[i])/(py[j]-py[i])*(px[j]-px[i]) < x:
    15321537                        inside = not inside
    1533 
     1538                   
    15341539        if inside: indices.append(k)
    15351540
    1536     if one_point:
     1541    if one_point: 
    15371542        return inside
    15381543    else:
    15391544        return indices
    1540 
     1545             
    15411546
    15421547#def remove_from(A, B):
     
    15471552#    ind = search_sorted(A, B)
    15481553
    1549 
     1554   
    15501555
    15511556def outside_polygon_old(point, polygon, closed = True, verbose = False):
    15521557    #OBSOLETED
    15531558    """Determine whether points are outside a polygon
    1554 
     1559   
    15551560    Input:
    15561561       point - Tuple of (x, y) coordinates, or list of tuples
    15571562       polygon - list of vertices of polygon
    1558        closed - (optional) determine whether points on boundary should be
    1559        regarded as belonging to the polygon (closed = True)
    1560        or not (closed = False)
    1561 
     1563       closed - (optional) determine whether points on boundary should be 
     1564       regarded as belonging to the polygon (closed = True) 
     1565       or not (closed = False) 
     1566   
    15621567    Output:
    15631568       If one point is considered, True or False is returned.
    1564        If multiple points are passed in, the function returns indices
    1565        of those points that fall outside the polygon
    1566 
     1569       If multiple points are passed in, the function returns indices 
     1570       of those points that fall outside the polygon     
     1571       
    15671572    Examples:
    1568        U = [[0,0], [1,0], [1,1], [0,1]] #Unit square
     1573       U = [[0,0], [1,0], [1,1], [0,1]] #Unit square   
    15691574       outside_polygon( [0.5, 0.5], U )
    15701575       will evaluate to False as the point 0.5, 0.5 is inside the unit square
     
    15721577       ouside_polygon( [1.5, 0.5], U )
    15731578       will evaluate to True as the point 1.5, 0.5 is outside the unit square
    1574 
     1579       
    15751580       outside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]], U )
    1576        will return the indices [1] as only the first and the last point
     1581       will return the indices [1] as only the first and the last point 
    15771582       is inside the unit square
    15781583    """
    15791584
    15801585    #FIXME: This is too slow
    1581 
     1586   
    15821587    res  = inside_polygon(point, polygon, closed, verbose)
    15831588
     
    15971602
    15981603    C-wrapper
    1599     """
     1604    """   
    16001605
    16011606    from Numeric import array, Float, reshape, zeros, Int
    1602 
    1603 
    1604     if verbose: print 'Checking input to inside_polygon'
     1607   
     1608
     1609    if verbose: print 'Checking input to inside_polygon'   
    16051610    #Input checks
    16061611    try:
    1607         point = array(point).astype(Float)
     1612        point = array(point).astype(Float)         
    16081613    except:
    16091614        msg = 'Point %s could not be converted to Numeric array' %point
    1610         raise msg
    1611 
     1615        raise msg       
     1616       
    16121617    try:
    1613         polygon = array(polygon).astype(Float)
     1618        polygon = array(polygon).astype(Float)             
    16141619    except:
    16151620        msg = 'Polygon %s could not be converted to Numeric array' %polygon
    1616         raise msg
    1617 
     1621        raise msg               
     1622   
    16181623    assert len(polygon.shape) == 2,\
    16191624       'Polygon array must be a 2d array of vertices: %s' %polygon
    16201625
    1621 
     1626       
    16221627    assert polygon.shape[1] == 2,\
    1623        'Polygon array must have two columns: %s' %polygon
     1628       'Polygon array must have two columns: %s' %polygon   
    16241629
    16251630
     
    16271632        one_point = True
    16281633        points = reshape(point, (1,2))
    1629     else:
     1634    else:       
    16301635        one_point = False
    16311636        points = point
     
    16371642    indices = zeros( points.shape[0], Int )
    16381643
    1639     if verbose: print 'Calling C-version of inside poly'
     1644    if verbose: print 'Calling C-version of inside poly' 
    16401645    count = inside_polygon(points, polygon, indices,
    16411646                           int(closed), int(verbose))
     
    16451650    else:
    16461651        if verbose: print 'Got %d points' %count
    1647 
     1652       
    16481653        return indices[:count]   #Return those indices that were inside
     1654
Note: See TracChangeset for help on using the changeset viewer.