def greater_equal(x1: Array, x2: Array, /) -> Array: """ Array API compatible wrapper for :py:func:`np.greater_equal <numpy.greater_equal>`. See its docstring for more information. """ if x1.dtype not in _numeric_dtypes or x2.dtype not in _numeric_dtypes: raise TypeError("Only numeric dtypes are allowed in greater_equal") # Call result type here just to raise on disallowed type combinations _result_type(x1.dtype, x2.dtype) x1, x2 = Array._normalize_two_args(x1, x2) return Array._new(np.greater_equal(x1._array, x2._array))
def test_bounding_box_outside(self): bounding_box = { 'rotation_matrix': [[1., 0., 0.], [0., -1., 0.], [0., 0., 1.]], 'translation_vector': [0., 0., 0.], 'size': [1., 1., 1.] } results = locate_points(mesh_prefix="test_tetra", pts_prefix="test_tetra_bbox_outside", chunk_size=5, bounding_box=bounding_box) assert (cp.greater_equal(results[1], 0.).all())
def __ge__(self, other): return cupy.greater_equal(self, other)
def evaluate_chunks( results: [cp.ndarray, cp.ndarray, cp.ndarray], # closest triangle, distance, projection all_pts: cp.ndarray = None, vertices: cp.ndarray = None, edges: cp.ndarray = None, edge_norms: cp.ndarray = None, edge_normssq: cp.ndarray = None, normals: cp.ndarray = None, norms: cp.ndarray = None, normssq: cp.ndarray = None, zero_tensor: cp.ndarray = None, one_tensor: cp.ndarray = None, tris: cp.ndarray = None, vertex_normals: cp.ndarray = None, bounding_box: dict = None, chunk_size: int = None, num_verts: int = None) -> None: # # Expand vertex normals if non empty if vertex_normals is not None: vertex_normals = vertex_normals[tris] vertex_normals = cp.tile(cp.expand_dims(vertex_normals, axis=2), (1, 1, chunk_size, 1)) # begin = time.time() # # Load and extend the batch num_chunks = all_pts.shape[0] // chunk_size for i in range(num_chunks): # # Get subset of the query points start_index = i * chunk_size end_index = (i + 1) * chunk_size pts = all_pts[start_index:end_index, :] # # Match the dimensions to those assumed above. # REPEATED REPEATED # [triangle_index, vert_index, querypoint_index, coordinates] pts = cp.tile(cp.expand_dims(pts, axis=(0, 1)), (num_verts, 3, 1, 1)) # # Compute the differences between # vertices on each triangle and the # points of interest # # [triangle_index, vert_index, querypoint_index, coordinates] # =================== # [:,0,:,:] = p - p1 # [:,1,:,:] = p - p2 # [:,2,:,:] = p - p3 diff_vectors = pts - vertices # # Compute alpha, beta, gamma barycentric = cp.empty(diff_vectors.shape) # # gamma = u x (p - p1) barycentric[:, 2, :, :] = cp.cross(edges[:, 0, :, :], diff_vectors[:, 0, :, :]) # beta = (p - p1) x v barycentric[:, 1, :, :] = cp.cross(diff_vectors[:, 0, :, :], edges[:, 1, :, :]) # alpha = w x (p - p2) barycentric[:, 0, :, :] = cp.cross(edges[:, 2, :, :], diff_vectors[:, 1, :, :]) barycentric = cp.divide( cp.sum(cp.multiply(barycentric, normals), axis=3), normssq) # # Test conditions less_than_one = cp.less_equal(barycentric, one_tensor) more_than_zero = cp.greater_equal(barycentric, zero_tensor) # # if 0 <= gamma and gamma <= 1 # and 0 <= beta and beta <= 1 # and 0 <= alpha and alpha <= 1: cond1 = cp.logical_and(less_than_one, more_than_zero) # # if gamma <= 0: cond2 = cp.logical_not(more_than_zero[:, 2, :]) cond2 = cp.tile(cp.expand_dims(cond2, axis=1), (1, 3, 1)) # # if beta <= 0: cond3 = cp.logical_not(more_than_zero[:, 1, :]) cond3 = cp.tile(cp.expand_dims(cond3, axis=1), (1, 3, 1)) # # if alpha <= 0: cond4 = cp.logical_not(more_than_zero[:, 0, :]) cond4 = cp.tile(cp.expand_dims(cond4, axis=1), (1, 3, 1)) # # Get the projections for each case xi = cp.empty(barycentric.shape) barycentric_ext = cp.tile(cp.expand_dims(barycentric, axis=3), (1, 1, 1, 3)) proj = cp.sum(cp.multiply(barycentric_ext, vertices), axis=1) # # if 0 <= gamma and gamma <= 1 # and 0 <= beta and beta <= 1 # and 0 <= alpha and alpha <= 1: xi[cond1] = barycentric[cond1] # # if gamma <= 0: # x = p - p1 # u = p2 - p1 # a = p1 # b = p2 t2 = cp.divide( # # u.dot(x) cp.sum(cp.multiply(edges[:, 0, :, :], diff_vectors[:, 0, :, :]), axis=2), edge_normssq[:, 0]) xi2 = cp.zeros((t2.shape[0], 3, t2.shape[1])) xi2[:, 0, :] = -t2 + 1 xi2[:, 1, :] = t2 # t2 = cp.tile(cp.expand_dims(t2, axis=2), (1, 1, 3)) lz = cp.less(t2, cp.zeros(t2.shape)) go = cp.greater(t2, cp.ones(t2.shape)) proj2 = vertices[:, 0, :, :] + cp.multiply(t2, edges[:, 0, :, :]) proj2[lz] = vertices[:, 0, :, :][lz] proj2[go] = vertices[:, 1, :, :][go] # xi[cond2] = xi2[cond2] proj[cp.swapaxes(cond2, 1, 2)] = proj2[cp.swapaxes(cond2, 1, 2)] # # if beta <= 0: # x = p - p1 # v = p3 - p1 # a = p1 # b = p3 t3 = cp.divide( # # v.dot(x) cp.sum(cp.multiply(edges[:, 1, :, :], diff_vectors[:, 0, :, :]), axis=2), edge_normssq[:, 1]) xi3 = cp.zeros((t3.shape[0], 3, t3.shape[1])) xi3[:, 0, :] = -t3 + 1 xi3[:, 2, :] = t3 # t3 = cp.tile(cp.expand_dims(t3, axis=2), (1, 1, 3)) lz = cp.less(t3, cp.zeros(t3.shape)) go = cp.greater(t3, cp.ones(t3.shape)) proj3 = vertices[:, 0, :, :] + cp.multiply(t3, edges[:, 1, :, :]) proj3[lz] = vertices[:, 0, :, :][lz] proj3[go] = vertices[:, 2, :, :][go] # xi[cond3] = xi3[cond3] proj[cp.swapaxes(cond3, 1, 2)] = proj3[cp.swapaxes(cond3, 1, 2)] # # if alpha <= 0: # y = p - p2 # w = p3 - p2 # a = p2 # b = p3 t4 = cp.divide( # # w.dot(y) cp.sum(cp.multiply(edges[:, 2, :, :], diff_vectors[:, 1, :, :]), axis=2), edge_normssq[:, 2]) xi4 = cp.zeros((t4.shape[0], 3, t4.shape[1])) xi4[:, 1, :] = -t4 + 1 xi4[:, 2, :] = t4 # t4 = cp.tile(cp.expand_dims(t4, axis=2), (1, 1, 3)) lz = cp.less(t4, cp.zeros(t4.shape)) go = cp.greater(t4, cp.ones(t4.shape)) proj4 = vertices[:, 1, :, :] + cp.multiply(t4, edges[:, 2, :, :]) proj4[lz] = vertices[:, 1, :, :][lz] proj4[go] = vertices[:, 2, :, :][go] # xi[cond4] = xi4[cond4] proj[cp.swapaxes(cond4, 1, 2)] = proj4[cp.swapaxes(cond4, 1, 2)] vec_to_point = pts[:, 0, :, :] - proj distances = cp.linalg.norm(vec_to_point, axis=2) # n = "\n" # print(f"{pts[:,0,:,:]=}") # print(f"{proj=}") # print(f"{pts[:,0,:,:] - proj=}") # print(f"{distances=}") min_distances = cp.min(distances, axis=0) closest_triangles = cp.argmin(distances, axis=0) projections = proj[closest_triangles, np.arange(chunk_size), :] # # Distinguish close triangles is_close = cp.isclose(distances, min_distances) # # Determine sign signed_normal = normals[:, 0, :, :] if vertex_normals is not None: signed_normal = cp.sum(vertex_normals.transpose() * xi.transpose(), axis=2).transpose() is_negative = cp.less_equal( cp.sum(cp.multiply(vec_to_point, signed_normal), axis=2), 0.) # # Combine is_close_and_negative = cp.logical_and(is_close, is_negative) # # Determine if inside is_inside = cp.all(cp.logical_or(is_close_and_negative, cp.logical_not(is_close)), axis=0) # # Overwrite the signs of points # that are outside of the box if bounding_box is not None: # # Extract rotation_matrix = cp.asarray(bounding_box['rotation_matrix']) translation_vector = cp.asarray(bounding_box['translation_vector']) size = cp.asarray(bounding_box['size']) # # Transform transformed_pts = cp.dot( all_pts[start_index:end_index, :] - translation_vector, rotation_matrix) # # Determine if outside bbox inside_bbox = cp.all(cp.logical_and( cp.less_equal(0., transformed_pts), cp.less_equal(transformed_pts, size)), axis=1) # # Treat points outside bbox as # being outside of lumen print(f"{inside_bbox=}") is_inside = cp.logical_and(is_inside, inside_bbox) # # Apply sign to indicate whether the distance is # inside or outside the mesh. min_distances[is_inside] = -1 * min_distances[is_inside] # # Emplace results # [triangle_index, vert_index, querypoint_index, coordinates] results[0][start_index:end_index] = closest_triangles results[1][start_index:end_index] = min_distances results[2][start_index:end_index, :] = projections
def test_outside(self): results = locate_points(mesh_prefix="test_tetra", pts_prefix="test_tetra_outside", chunk_size=100) assert (cp.greater_equal(results[1], 0.).all())