Detection of groups of connected spheres


I need to detect which spheres are connected to each other. If we have:

radii = np.array([2, 1, 1, 2, 2, 0.5])
poss = np.array([[7, 7, 7], [7.5, 8.5, 6], [0, 0, 0], [-1, -2, -1], [1, 1, 1], [2, 1, 3]])

enter image description here

I want a Boolean array (shape = (number of groups, number of spheres)) or array/lists of arrays/lists of indices that shows which of the spheres are connected. So, the expected results for this example must be something like:

Boolean_array = np.array([[1, 1, 0, 0, 0, 0], [0, 0, 1, 1, 1, 1]], dtype=bool)

object_array = np.array([[0, 1], [2, 3, 4, 5]])

I tried to find a solution with networkx (I’m not very familiar with it) and IDK if this library can help where we have spheres with different radii. I guess, returned ends_ind in my previous code can be helpful in this regard and I tried to use that as:

G = nx.Graph([*ends_ind])
L = [nx.node_connected_component(G, 0)]
for i in range(len(radii)):
    iter = 0
    for j in L:
        if i in j:
            iter += 1
    if iter == 0:
        L.append(nx.node_connected_component(G, i))

Which will not work. The error:

Traceback (most recent call last):
  File "C:/Users/Ali/Desktop/", line 31, in <module>
    L.append(nx.node_connected_component(G, i))
  File "<class 'networkx.utils.decorators.argmap'> compilation 8", line 4, in argmap_node_connected_component_5
  File "C:\Users\Ali\anaconda3\envs\PFC_FiPy\lib\site-packages\networkx\algorithms\components\", line 185, in node_connected_component
    return _plain_bfs(G, n)
  File "C:\Users\Ali\anaconda3\envs\PFC_FiPy\lib\site-packages\networkx\algorithms\components\", line 199, in _plain_bfs
  File "C:\Users\Ali\anaconda3\envs\PFC_FiPy\lib\site-packages\networkx\classes\", line 82, in __getitem__
    return AtlasView(self._atlas[name])
KeyError: 11

Since using my previous code with other libraries will be an inefficient code (if it can solve the issue), I am seeking for any libraries, e.g. networkx, or methods that can do it in a more efficient way, if possible.

What is the best way to get my expected results, particularly for large number of spheres (~100000).


You’re trying to utilize networkx too early, here. First, you should calculate the geometrical distances for each pair of spheres. A useful trick for this is:

xyz_distances = poss.reshape(6, 1, 3) - poss.reshape(1, 6, 3)
distances = np.linalg.norm(xyz_distances, axis=2)

This gets you a symmetric 6×6 array of Euclidean distances between the sphere centers. Now, we need to compare the maximum possible distances. This is just the sum of radii for each pair of spheres, once again a 6×6 array, which we can calculate as

maximum_distances = radii.reshape(6, 1) + radii.reshape(1, 6)

And now we can compare the two:

>>> connections = distances < maximum_distances
>>> connections
array([[ True,  True, False, False, False, False],
       [ True,  True, False, False, False, False],
       [False, False,  True,  True,  True, False],
       [False, False,  True,  True, False, False],
       [False, False,  True, False,  True,  True],
       [False, False, False, False,  True,  True]])

Which translates to two groups, just like you wanted – and you can get your second expected array via

>>> G = nx.Graph(connections)
>>> list(nx.connected_components(G))
[{0, 1}, {2, 3, 4, 5}]

Note that this whole thing is going to scale as N^2 in the number of spheres, and you might need to optimize that somehow (say, via scipy.spatial.ckdtree).

Answered By – Dominik StaƄczak

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published