source: inundation/ga/storm_surge/pyvolution/util_ext.c @ 1065

Last change on this file since 1065 was 1032, checked in by ole, 20 years ago

Changed int* to long* for use with 64 bit

File size: 7.2 KB
Line 
1// Python - C extension for finite_volumes util module.
2//
3// To compile (Python2.3):
4//  gcc -c util_ext.c -I/usr/include/python2.3 -o util_ext.o -Wall -O
5//  gcc -shared util_ext.o  -o util_ext.so
6//
7// See the module util.py
8//
9//
10// Ole Nielsen, GA 2004
11//
12//NOTE: On 64 bit systems use long* instead of int* for Numeric arrays
13//this will also work on 32 bit systems
14
15
16#include "Python.h"
17#include "Numeric/arrayobject.h"
18#include "math.h"
19
20//Shared snippets
21#include "util_ext.h"
22
23
24
25int _point_on_line(double x, double y,
26                   double x0, double y0,
27                   double x1, double y1) {
28  /*Determine whether a point is on a line segment
29
30    Input: x, y, x0, x0, x1, y1: where
31        point is given by x, y
32        line is given by (x0, y0) and (x1, y1)
33
34  */
35
36  double a0, a1, a_normal0, a_normal1, b0, b1, len_a, len_b;
37
38  a0 = x - x0;
39  a1 = y - y0;
40
41  a_normal0 = a1;
42  a_normal1 = -a0;
43
44  b0 = x1 - x0;
45  b1 = y1 - y0;
46
47  if ( a_normal0*b0 + a_normal1*b1 == 0 ) {
48    //Point is somewhere on the infinite extension of the line
49
50    len_a = sqrt(a0*a0 + a1*a1);
51    len_b = sqrt(b0*b0 + b1*b1);
52
53    if (a0*b0 + a1*b1 >= 0 && len_a <= len_b) {
54      return 1;
55    } else {
56      return 0;
57    }
58  } else {
59    return 0;
60  }
61}
62
63
64
65int _inside_polygon(int M,           // Number of points
66                    int N,           // Number of polygon vertices
67                    double* points,
68                    double* polygon,
69                    long* indices,    // M-Array for storage indices
70                    int closed,
71                    int verbose) {
72
73  double minpx, maxpx, minpy, maxpy, x, y, px_i, py_i, px_j, py_j;
74  int i, j, k, count, inside;
75
76  //Find min and max of poly used for optimisation when points
77  //are far away from polygon
78
79
80  minpx = polygon[0]; maxpx = minpx;
81  minpy = polygon[1]; maxpy = minpy;
82
83  for (i=0; i<N; i++) {
84    px_i = polygon[2*i];
85    py_i = polygon[2*i + 1];
86
87    if (px_i < minpx) minpx = px_i;
88    if (px_i > maxpx) maxpx = px_i;
89    if (py_i < minpy) minpy = py_i;
90    if (py_i > maxpy) maxpy = py_i;
91  }
92
93  //Begin main loop (for each point)
94  count = 0;
95  for (k=0; k<M; k++) {
96    //FIXME: Do this later
97    //if (verbose){
98    //  if (k %((M+10)/10)==0: print 'Doing %d of %d' %(k, M)
99
100    x = points[2*k];
101    y = points[2*k + 1];
102
103    inside = 0;
104
105    //Optimisation
106    if ((x > maxpx) || (x < minpx)) continue;
107    if ((y > maxpy) || (y < minpy)) continue;
108
109    //Check polygon
110    for (i=0; i<N; i++) {
111      //printf("k,i=%d,%d\n", k, i);
112      j = (i+1)%N;
113
114      px_i = polygon[2*i];
115      py_i = polygon[2*i+1];
116      px_j = polygon[2*j];
117      py_j = polygon[2*j+1];
118
119      //Check for case where point is contained in line segment
120      if (_point_on_line(x, y, px_i, py_i, px_j, py_j)) {
121        if (closed == 1) {
122          inside = 1;
123        } else {
124          inside = 0;
125        }
126        break;
127      } else {
128        //Check if truly inside polygon
129        if ( ((py_i < y) && (py_j >= y)) ||
130             ((py_j < y) && (py_i >= y)) ) {
131          if (px_i + (y-py_i)/(py_j-py_i)*(px_j-px_i) < x)
132            inside = 1-inside;
133        }
134      }
135    }
136    if (inside == 1) {
137      indices[count] = k;
138      count++;
139    }
140  } // End k
141
142  return count;
143}
144
145
146
147// Gateways to Python
148PyObject *point_on_line(PyObject *self, PyObject *args) {
149  //
150  // point_on_line(x, y, x0, y0, x1, y1)
151  //
152
153  double x, y, x0, y0, x1, y1;
154  int res;
155  PyObject *result;
156
157  // Convert Python arguments to C
158  if (!PyArg_ParseTuple(args, "dddddd", &x, &y, &x0, &y0, &x1, &y1))
159    return NULL;
160
161
162  // Call underlying routine
163  res = _point_on_line(x, y, x0, y0, x1, y1);
164
165  // Return values a and b
166  result = Py_BuildValue("i", res);
167  return result;
168}
169
170
171
172PyObject *inside_polygon(PyObject *self, PyObject *args) {
173  //def inside_polygon(point, polygon, closed, verbose, one_point):
174  //  """Determine whether points are inside or outside a polygon
175  //
176  //  Input:
177  //     point - Tuple of (x, y) coordinates, or list of tuples
178  //     polygon - list of vertices of polygon
179  //     one_poin - If True Boolean value should be returned
180  //                If False, indices of points inside returned
181  //     closed - (optional) determine whether points on boundary should be
182  //     regarded as belonging to the polygon (closed = True)
183  //     or not (closed = False)
184
185  //
186  //  Output:
187  //     If one point is considered, True or False is returned.
188  //     If multiple points are passed in, the function returns indices
189  //     of those points that fall inside the polygon
190  //
191  //  Examples:
192  //     inside_polygon( [0.5, 0.5], [[0,0], [1,0], [1,1], [0,1]] )
193  //     will evaluate to True as the point 0.5, 0.5 is inside the unit square
194  //
195  //     inside_polygon( [[0.5, 0.5], [1, -0.5], [0.3, 0.2]] )
196  //     will return the indices [0, 2] as only the first and the last point
197  //     is inside the unit square
198  //
199  //  Remarks:
200  //     The vertices may be listed clockwise or counterclockwise and
201  //     the first point may optionally be repeated.
202  //     Polygons do not need to be convex.
203  //     Polygons can have holes in them and points inside a hole is
204  //     regarded as being outside the polygon.
205  //
206  //
207  //  Algorithm is based on work by Darel Finley,
208  //  http://www.alienryderflex.com/polygon/
209  //
210  //
211
212  PyArrayObject
213    *point,
214    *polygon,
215    *indices;
216
217  int closed, verbose; //Flags
218  int count, M, N;
219
220  // Convert Python arguments to C
221  if (!PyArg_ParseTuple(args, "OOOii",
222                        &point,
223                        &polygon,
224                        &indices,
225                        &closed,
226                        &verbose))
227    return NULL;
228
229  M = point -> dimensions[0];    //Number of points
230  N = polygon -> dimensions[0];  //Number of vertices in polygon
231
232  //printf("M=%d, N=%d\n", M, N);
233  //Call underlying routine
234  count = _inside_polygon(M, N,
235                          (double*) point -> data,
236                          (double*) polygon -> data,
237                          (long*) indices -> data,
238                          closed, verbose);
239
240  //NOTE: return number of points inside..
241  //printf("COunt=%d\n", count);
242  return Py_BuildValue("i", count);
243}
244
245
246
247PyObject *gradient(PyObject *self, PyObject *args) {
248  //
249  // a,b = gradient(x0, y0, x1, y1, x2, y2, q0, q1, q2)
250  //
251
252  double x0, y0, x1, y1, x2, y2, q0, q1, q2, a, b;
253  PyObject *result;
254
255  // Convert Python arguments to C
256  if (!PyArg_ParseTuple(args, "ddddddddd", &x0, &y0, &x1, &y1, &x2, &y2,
257                        &q0, &q1, &q2))
258    return NULL;
259
260
261  // Call underlying routine
262  _gradient(x0, y0, x1, y1, x2, y2,
263            q0, q1, q2, &a, &b);
264
265  // Return values a and b
266  result = Py_BuildValue("dd", a, b);
267  return result;
268}
269
270
271// Method table for python module
272static struct PyMethodDef MethodTable[] = {
273  /* The cast of the function is necessary since PyCFunction values
274   * only take two PyObject* parameters, and rotate() takes
275   * three.
276   */
277
278  //{"rotate", (PyCFunction)rotate, METH_VARARGS | METH_KEYWORDS, "Print out"},
279  {"gradient", gradient, METH_VARARGS, "Print out"},
280  {"point_on_line", point_on_line, METH_VARARGS, "Print out"},
281  {"inside_polygon", inside_polygon, METH_VARARGS, "Print out"},
282  {NULL, NULL, 0, NULL}   /* sentinel */
283};
284
285
286
287// Module initialisation
288void initutil_ext(void){
289  Py_InitModule("util_ext", MethodTable);
290
291  import_array();     //Necessary for handling of NumPY structures
292}
Note: See TracBrowser for help on using the repository browser.