cdef extern from "cOctree.h":
cdef cppclass cOctNode:
double size
int level
int nid
vector[double] position
vector[cOctNode] branches
vector[int] data
int numPolys()
bint isLeafNode()
cdef cppclass cOctree:
cOctree(vector[vector[double]] vertexCoords3D, vector[vector[int]] polyConnectivity)
int numPolys()
cOctNode root
cdef class PyOctree:
cdef cOctree *thisptr
def __cinit__(self,double[:,::1] _vertexCoords3D, int[:,::1] _polyConnectivity):
cdef int i, j
cdef vector[double] coords
cdef vector[vector[double]] vertexCoords3D
coords.resize(3)
for i in range(_vertexCoords3D.shape[0]):
for j in range(3):
coords[j] = _vertexCoords3D[i,j]
vertexCoords3D.push_back(coords)
cdef vector[int] connect
cdef vector[vector[int]] polyConnectivity
connect.resize(3)
for i in range(_polyConnectivity.shape[0]):
for j in range(3):
connect[j] = _polyConnectivity[i,j]
polyConnectivity.push_back(connect)
self.thisptr = new cOctree(vertexCoords3D,polyConnectivity)
def __dealloc__(self):
del self.thisptr
cpdef int numPolys(self):
return self.thisptr.numPolys()
property root:
def __get__(self):
cdef cOctNode *node = &self.thisptr.root
return PyOctnode_Init(node)
cdef class PyOctnode:
cdef cOctNode *thisptr
def __cinit__(self):
# self.thisptr will be set by global function PyOctnode_Init to point
# to an existing cOctNode object
self.thisptr = NULL
def __init__(self):
pass
property isLeaf:
def __get__(self):
return self.thisptr.isLeafNode()
property branches:
def __get__(self):
branches = []
cdef int numBranches = self.thisptr.branches.size()
cdef int i
cdef cOctNode *node = NULL
for i in range(numBranches):
node = &self.thisptr.branches[i]
branches.append(PyOctnode_Init(node))
return branches
property polyList:
def __get__(self):
cdef list polyList = []
cdef int numPolys = self.thisptr.numPolys()
cdef int i
for i in range(numPolys):
polyList.append(self.thisptr.data[i])
return polyList
property level:
def __get__(self):
return self.thisptr.level
property nid:
def __get__(self):
return self.thisptr.nid
property numPolys:
def __get__(self):
return self.thisptr.numPolys()
property size:
def __get__(self):
return self.thisptr.size
property position:
def __get__(self):
cdef int dims = self.thisptr.position.size()
cdef int i
cdef np.ndarray[float64,ndim=1] position = np.zeros(3,dtype=np.float64)
for i in range(dims):
position[i] = self.thisptr.position[i]
return position
def __dealloc__(self):
print 'PyOctNode __dealloc__(): This will cause a crash'
#del self.thisptr
cdef PyOctnode_Init(cOctNode *node):
result = PyOctnode()
result.thisptr = node
return result
In this case, why would you need __dealloc__ at all? The C++ code that
creates and manages cOctNodes should take care of deallocation, and make
sure that the objects remain alive until the Python side doesn't need
them anymore. If my assertions are correct and you free these objects in
__dealloc__, of course you're gonna get crashes...
Consider the following:tree = Octree()root = tree.root()del tree# what will this do (boom!)?root.positionI think this will fix it:cdef class cOctNode:cdef object treedef __cinit__(self, tree):self.tree = tree
Because my cOctree is the one that destroys all the cOctnodes, if the PyOctree gets deleted, then there will be no way of then releasing the memory for the copy of root because PyOctNode doesn't do anything in the __dealloc__ function. This probably my main problem, and related to the issue that you have raised. Any ideas?