@@ -102,6 +102,104 @@ def sort_point_pairs(
102102 return sorted_lines , sort_ind
103103
104104
105+ def sort_multiple_point_pairs (lines : np .ndarray ) -> np .ndarray :
106+ """Function to sort multiple pairs of points to form circular chains.
107+
108+ The routine contains essentially the same functionality as sort_point_pairs,
109+ but stripped down to the special case of circular chains. Differently to
110+ sort_point_pairs, this variant sorts an arbitrary amount of independent
111+ point pairs. The chains are restricted by the assumption that each contains
112+ equally many line segments. Finally, this routine uses numba.
113+
114+ Parameters:
115+ lines (np.ndarray): Array of size 2 * num_chains x num_lines_per_chain,
116+ containing node indices. For each pair of two rows, each column
117+ represents a line segment connectng the two nodes in the two entries
118+ of this column.
119+
120+ Returns:
121+ np.ndarray: Sorted version of lines, where for each chain, the collection
122+ of l
123+
124+ Raises:
125+ ImportError ifine segments has been potentially flipped and sorted.
126+ """
127+
128+ try :
129+ import numba
130+ except ImportError :
131+ raise ImportError ("Numba not available on the system" )
132+
133+ @numba .njit ("f8[:,:](i4[:,:])" , cache = True )
134+ def _function_to_compile (lines ):
135+ """
136+ Copy of pp.utils.sort_points.sort_point_pairs. This version is extended
137+ to multiple chains. Each chain is implicitly assumed to be circular.
138+ """
139+
140+ # Retrieve number of chains and lines per chain from the shape.
141+ # Implicitly expect that all chains have the same length
142+ num_chains , chain_length = lines .shape
143+ # Since for each chain lines includes two rows, divide by two
144+ num_chains = int (num_chains / 2 )
145+
146+ # Initialize array of sorted lines to be the final output
147+ sorted_lines = np .zeros ((2 * num_chains , chain_length ))
148+ # Fix the first line segment for each chain and identify
149+ # it as in place regarding the sorting.
150+ sorted_lines [:, 0 ] = lines [:, 0 ]
151+ # Keep track of which lines have been fixed and which are still candidates
152+ found = np .zeros (chain_length )
153+ found [0 ] = 1
154+
155+ # Loop over chains and consider each chain separately.
156+ for c in range (num_chains ):
157+ # Initialize found making any line segment aside of the first a candidate
158+ found [1 :] = 0
159+
160+ # Define the end point of the previous and starting point for the next
161+ # line segment
162+ prev = sorted_lines [2 * c + 1 , 0 ]
163+
164+ # The sorting algorithm: Loop over all positions in the chain to be set next.
165+ # Find the right candidate to be moved to this position and possibly flipped
166+ # if needed. A candidate is identified as fitting if it contains one point
167+ # equal to the current starting point. This algorithm uses a double loop,
168+ # which is the most naive approach. However, assume chain_length is in
169+ # general small.
170+ for i in range (1 , chain_length ): # The first line has already been found
171+ for j in range (
172+ 1 , chain_length
173+ ): # The first line has already been found
174+ # A candidate line segment with matching start and end point
175+ # in the first component of the point pair.
176+ if np .abs (found [j ]) < 1e-6 and lines [2 * c , j ] == prev :
177+ # Copy the segment to the right place
178+ sorted_lines [2 * c : 2 * c + 2 , i ] = lines [2 * c : 2 * c + 2 , j ]
179+ # Mark as used
180+ found [j ] = 1
181+ # Define the starting point for the next line segment
182+ prev = lines [2 * c + 1 , j ]
183+ break
184+ # A candidate line segment with matching start and end point
185+ # in the second component of the point pair.
186+ elif np .abs (found [j ]) < 1e-6 and lines [2 * c + 1 , j ] == prev :
187+ # Flip and copy the segment to the right place
188+ sorted_lines [2 * c , i ] = lines [2 * c + 1 , j ]
189+ sorted_lines [2 * c + 1 , i ] = lines [2 * c , j ]
190+ # Mark as used
191+ found [j ] = 1
192+ # Define the starting point for the next line segment
193+ prev = lines [2 * c , j ]
194+ break
195+
196+ # Return the sorted lines defining chains.
197+ return sorted_lines
198+
199+ # Run numba compiled function
200+ return _function_to_compile (lines )
201+
202+
105203def sort_point_plane (
106204 pts : np .ndarray ,
107205 centre : np .ndarray ,
0 commit comments