2D c-arrays in cython

1,527 views
Skip to first unread message

flabowski

unread,
Mar 17, 2017, 12:31:56 PM3/17/17
to cython-users
Hi there,

I am using Angus J's Polygonclipper in cython (or rather the cython wrapper "pyclipper": https://pypi.python.org/pypi/pyclipper).
See http://www.angusj.com/delphi/clipper.php

The function in cython gets a polygon, then calculates some computaional extensive stuff and finally returns the area of the resulting polygon:
pyclipper_cython.pyx
cimport cython
import numpy as np
cimport numpy as np
import pyclipper
pc = pyclipper.Pyclipper()
from libc.stdlib cimport malloc, free
DTYPE_I = np.int
ctypedef np.int_t DTYPE_I_t


@cython.cdivision(True)
@cython.boundscheck(False)
@cython.wraparound(False)
def my_function(np.ndarray[DTYPE_I_t, ndim=2] polygon):
    cdef int rows = polygon.shape[0]
    cdef int columns = polygon.shape[1]
   
    # found here: http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/
    cdef int **solution_polygon = <int **>malloc(rows * sizeof(int *))
    for i in range(rows):
         solution_polygon[i] = <int *>malloc(columns * sizeof(int))

    # some extensive operations ...
    for i in range(rows):
          for j in range(columns):
             solution_polygon[i][j] = polygon[i, j] + 1

    # for the sake of simplicity, let us just calculate the area of the polygon:
    area =  pyclipper.Area(solution_polygon)

as usually i call this funtion like this:
call_my_function.py
import numpy as np
import pyximport
pyximport.install(setup_args={"include_dirs":np.get_include()}, reload_support=True)
import pyclipper_cython

my_polygon = np.array([[190, 210], [240, 210], [240, 130], [190, 130]], dtype=np.int)
pyclipper_cython.my_funtion(my_polygon)

unfortunately this fails with the message:

Error compiling Cython file:
------------------------------------------------------------
...
    for i in range(rows):
          for j in range(columns):
             solution_polygon[i][j] = polygon[i, j]+3

    # for the sake of simplicity, let us just calculate the area of the polygon:
    area =  pyclipper.Area(solution_polygon)
                                          ^
------------------------------------------------------------

pyclipper_cython.pyx:35:43: Cannot convert 'int **' to Python object


Any suggestions on how i would be able to work with c-arrays?
many thanks!

Chris Barker

unread,
Mar 17, 2017, 2:29:17 PM3/17/17
to cython-users
On Thu, Mar 16, 2017 at 3:20 AM, flabowski <floria...@t-online.de> wrote:
I am using Angus J's Polygonclipper in cython (or rather the cython wrapper "pyclipper": https://pypi.python.org/pypi/pyclipper).
See http://www.angusj.com/delphi/clipper.php

If you are using cython, maybe you should call the C++ code directly, rather than calling python from cython that is calling C++...

but anyway, this should be abel to work this way.

a couple intermediate comments:

The function in cython gets a polygon, then calculates some computaional extensive stuff and finally returns the area of the resulting polygon:
pyclipper_cython.pyx
cimport cython
import numpy as np
cimport numpy as np
import pyclipper
pc = pyclipper.Pyclipper()
from libc.stdlib cimport malloc, free
DTYPE_I = np.int
ctypedef np.int_t DTYPE_I_t

why the extra typedef? but anyway....
 
@cython.cdivision(True)
@cython.boundscheck(False)
@cython.wraparound(False)
def my_function(np.ndarray[DTYPE_I_t, ndim=2] polygon):
    cdef int rows = polygon.shape[0]
    cdef int columns = polygon.shape[1]
   
    # found here: http://www.geeksforgeeks.org/dynamically-allocate-2d-array-c/
    cdef int **solution_polygon = <int **>malloc(rows * sizeof(int *))

                  so solution_polygon is now a pointer to a pointer to an array of ints.

    for i in range(rows):
         solution_polygon[i] = <int *>malloc(columns * sizeof(int))

    # some extensive operations ...
    for i in range(rows):
          for j in range(columns):
             solution_polygon[i][j] = polygon[i, j] + 1

    # for the sake of simplicity, let us just calculate the area of the polygon:
    area =  pyclipper.Area(solution_polygon)

so now you are calling pyclipper.Area() and passing in a pointer to a pointer of ints. but what does pyclipper.Area expect? It's a cython wrapper, so I assume this is a pure python call -- so it is expecting a python object, not a C pointer.

So you need to look at the pyclipper code (Or docs) and see what it is expecting -- I'm going to guess it's either a numpy array or a polygon object defined by the module.

Then you need to write code that creates the object it wants from your C pointer.

if it's a numpy array, that is documented, but I"d suggest that rather than using your C pointer directly in your code, you create a memoryview, and work with that.

-CHB


--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R            (206) 526-6959   voice
7600 Sand Point Way NE   (206) 526-6329   fax
Seattle, WA  98115       (206) 526-6317   main reception

Chris....@noaa.gov
Reply all
Reply to author
Forward
0 new messages