Ignore:
Timestamp:
Mar 4, 2005, 12:20:11 PM (20 years ago)
Author:
ole
Message:

Optimised inside_polygon in C and tested

Location:
inundation/ga/storm_surge/pyvolution
Files:
3 edited

Legend:

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

    r998 r999  
    826826        polygon = [[0,0], [1,0], [1,1], [0,1]]
    827827
    828 
    829         R = inside_polygon( (0.5, 0.5), polygon)
    830         print 'Inside = ', R
    831         print
    832        
    833         R = inside_polygon( (0.5, 0.5), polygon)
    834         print 'Inside = ', R
    835         print
    836 
    837         import sys; sys.exit()
    838828        assert inside_polygon( (0.5, 0.5), polygon )
    839829        assert not inside_polygon( (0.5, 1.5), polygon )   
     
    953943#-------------------------------------------------------------
    954944if __name__ == "__main__":
    955     suite = unittest.makeSuite(TestCase,'test_inside_polygon_main')
     945    #suite = unittest.makeSuite(TestCase,'test_inside_polygon_main')
     946    suite = unittest.makeSuite(TestCase,'test')
    956947    runner = unittest.TextTestRunner()
    957948    runner.run(suite)
  • inundation/ga/storm_surge/pyvolution/util.py

    r997 r999  
    8787
    8888    #FIXME (OLE): Should check origin of domain against that of file
    89 
     89    #In fact, this is where origin should be converted to that of domain
     90    #Also, check that file covers domain fully.
    9091   
    9192    assert type(filename) == type(''),\
     
    974975    py = polygon[:,1]   
    975976
    976     #Used for an optimisation when points are far away from polgon
     977    #Used for an optimisation when points are far away from polygon
    977978    minpx = min(px); maxpx = max(px)
    978979    minpy = min(py); maxpy = max(py)   
     
    10221023             
    10231024
     1025
     1026def inside_polygon_c(point, polygon, closed = True, verbose = False):
     1027    """Determine whether points are inside or outside a polygon
     1028
     1029    C-wrapper
     1030    """   
     1031
     1032    from Numeric import array, Float, reshape, zeros, Int
     1033   
     1034   
     1035    #Input checks
     1036    try:
     1037        point = array(point).astype(Float)         
     1038    except:
     1039        msg = 'Point %s could not be converted to Numeric array' %point
     1040        raise msg       
     1041       
     1042    try:
     1043        polygon = array(polygon).astype(Float)             
     1044    except:
     1045        msg = 'Polygon %s could not be converted to Numeric array' %polygon
     1046        raise msg               
     1047   
     1048    assert len(polygon.shape) == 2,\
     1049       'Polygon array must be a 2d array of vertices: %s' %polygon
     1050
     1051       
     1052    assert polygon.shape[1] == 2,\
     1053       'Polygon array must have two columns: %s' %polygon   
     1054
     1055
     1056    if len(point.shape) == 1:
     1057        one_point = True
     1058        points = reshape(point, (1,2))
     1059    else:       
     1060        one_point = False
     1061        points = point
     1062
     1063    from util_ext import inside_polygon
     1064
     1065    indices = zeros( points.shape[0], Int )
     1066
     1067    count = inside_polygon(points, polygon, indices,
     1068                           int(closed), int(verbose))
     1069
     1070    #print 'O', point, count
     1071
     1072    if one_point:
     1073        return count == 1
     1074    else:
     1075        return indices[:count]
     1076
    10241077class Polygon_function:
    10251078    """Create callable object f: x,y -> z, where a,y,z are vectors and
     
    11341187    Examples:
    11351188       populate_polygon( [[0,0], [1,0], [1,1], [0,1]], 5 )
    1136        will return five randomly sleected points inside the unit square
     1189       will return five randomly selected points inside the unit square
    11371190    """
    11381191
     
    11831236
    11841237
    1185 
    1186 
    11871238##############################################
    11881239#Initialise module
     
    11901241import compile
    11911242if compile.can_use_C_extension('util_ext.c'):
    1192     from util_ext import gradient, point_on_line
     1243    from util_ext import gradient, point_on_line
     1244    inside_polygon = inside_polygon_c
    11931245else:
    11941246    gradient = gradient_python
  • inundation/ga/storm_surge/pyvolution/util_ext.c

    r671 r999  
    5959
    6060
     61int _inside_polygon(int M,           // Number of points
     62                    int N,           // Number of polygon vertices
     63                    double* points,
     64                    double* polygon,
     65                    int* indices,    // M-Array for storage indices
     66                    int closed,
     67                    int verbose) {
     68 
     69  double minpx, maxpx, minpy, maxpy, x, y, px_i, py_i, px_j, py_j;
     70  int i, j, k, count, inside;
     71 
     72  //Find min and max of poly used for optimisation when points
     73  //are far away from polygon
     74 
     75 
     76  minpx = polygon[0]; maxpx = minpx;
     77  minpy = polygon[1]; maxpy = minpy; 
     78 
     79  for (i=0; i<N; i++) {
     80    px_i = polygon[2*i];
     81    py_i = polygon[2*i + 1];
     82 
     83    if (px_i < minpx) minpx = px_i;
     84    if (px_i > maxpx) maxpx = px_i;   
     85    if (py_i < minpy) minpy = py_i;
     86    if (py_i > maxpy) maxpy = py_i;       
     87  }
     88 
     89  //Begin main loop (for each point)
     90  count = 0;
     91  for (k=0; k<M; k++) {
     92    //FIXME: Do this later
     93    //if (verbose){
     94    //  if (k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M)
     95       
     96    x = points[2*k];
     97    y = points[2*k + 1];       
     98
     99    inside = 0;
     100
     101    //Optimisation
     102    if ((x > maxpx) || (x < minpx)) continue;
     103    if ((y > maxpy) || (y < minpy)) continue;       
     104
     105    //Check polygon
     106    for (i=0; i<N; i++) {
     107      //printf("k,i=%d,%d\n", k, i);
     108      j = (i+1)%N;
     109     
     110      px_i = polygon[2*i];
     111      py_i = polygon[2*i+1];
     112      px_j = polygon[2*j];
     113      py_j = polygon[2*j+1];     
     114     
     115      //Check for case where point is contained in line segment
     116      if (_point_on_line(x, y, px_i, py_i, px_j, py_j)) {
     117        if (closed == 1) {
     118          inside = 1;
     119        } else {
     120          inside = 0;
     121        }
     122        break; 
     123      } else {   
     124        //Check if truly inside polygon             
     125        if ( ((py_i < y) && (py_j >= y)) ||
     126             ((py_j < y) && (py_i >= y)) ) {
     127          if (px_i + (y-py_i)/(py_j-py_i)*(px_j-px_i) < x)
     128            inside = 1-inside;
     129        }
     130      }
     131    }
     132    if (inside == 1) {
     133      indices[count] = k;
     134      count++;
     135    }       
     136  } // End k
     137 
     138  return count;
     139}
     140
     141
     142
    61143// Gateways to Python
    62144PyObject *point_on_line(PyObject *self, PyObject *args) {
     
    81163  return result;
    82164}
     165
     166
     167
     168PyObject *inside_polygon(PyObject *self, PyObject *args) {
     169  //def inside_polygon(point, polygon, closed, verbose, one_point): 
     170  //  """Determine whether points are inside or outside a polygon
     171  // 
     172  //  Input:
     173  //     point - Tuple of (x, y) coordinates, or list of tuples
     174  //     polygon - list of vertices of polygon
     175  //     one_poin - If True Boolean value should be returned
     176  //                If False, indices of points inside returned
     177  //     closed - (optional) determine whether points on boundary should be
     178  //     regarded as belonging to the polygon (closed = True)
     179  //     or not (closed = False)
     180 
     181  // 
     182  //  Output:
     183  //     If one point is considered, True or False is returned.
     184  //     If multiple points are passed in, the function returns indices
     185  //     of those points that fall inside the polygon     
     186  //     
     187  //  Examples:
     188  //     inside_polygon( [0.5, 0.5], [[0,0], [1,0], [1,1], [0,1]] )
     189  //     will evaluate to True as the point 0.5, 0.5 is inside the unit square
     190  //     
     191  //     inside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]] )
     192  //     will return the indices [0, 2] as only the first and the last point
     193  //     is inside the unit square
     194  //     
     195  //  Remarks:
     196  //     The vertices may be listed clockwise or counterclockwise and
     197  //     the first point may optionally be repeated.   
     198  //     Polygons do not need to be convex.
     199  //     Polygons can have holes in them and points inside a hole is
     200  //     regarded as being outside the polygon.               
     201  //           
     202  //     
     203  //  Algorithm is based on work by Darel Finley,
     204  //  http://www.alienryderflex.com/polygon/
     205  //
     206  //
     207 
     208  PyArrayObject
     209    *point,
     210    *polygon,
     211    *indices;
     212   
     213  int closed, verbose; //Flags     
     214  int count, M, N;
     215 
     216  // Convert Python arguments to C 
     217  if (!PyArg_ParseTuple(args, "OOOii",
     218                        &point,
     219                        &polygon,
     220                        &indices,
     221                        &closed,
     222                        &verbose)) 
     223    return NULL;
     224
     225  M = point -> dimensions[0];    //Number of points         
     226  N = polygon -> dimensions[0];  //Number of vertices in polygon       
     227
     228  //printf("M=%d, N=%d\n", M, N);
     229  // Call underlying routine
     230  count = _inside_polygon(M, N,
     231                          (double*) point -> data,
     232                          (double*) polygon -> data,
     233                          (int*) indices -> data,
     234                          closed, verbose);
     235                           
     236  //NOTE: return number of points inside..
     237  //printf("COunt=%d\n", count);
     238  return Py_BuildValue("i", count);
     239}
     240
    83241
    84242
     
    117275  {"gradient", gradient, METH_VARARGS, "Print out"},   
    118276  {"point_on_line", point_on_line, METH_VARARGS, "Print out"},     
     277  {"inside_polygon", inside_polygon, METH_VARARGS, "Print out"},     
    119278  {NULL, NULL, 0, NULL}   /* sentinel */
    120279};
Note: See TracChangeset for help on using the changeset viewer.