def get_normal(self): k_test = math.approximate_normal(self-self.centroid) i = math.normalize(self[:, 0, None] - self.centroid) n = math.normalize( self[:, self.shape[-1]//4, None] - self.centroid) k_test = math.normalize( math.cross(i, n)) j_test = math.cross(k_test, i) alpha1 = math.smallest_angle_between_vectors(j_test, n) alpha2 = math.smallest_angle_between_vectors(-j_test, n) if alpha1 < alpha2: return arrays.Vector(math.normalize(k_test)) else: return arrays.Vector(math.normalize(-k_test))
def oriented_transport_frames(self, origin, jVector, return_index=True): origin_id = np.argmin(math.l2_norm( self - arrays.ColumnVector(origin) )) transportFrames = self.transport_frames() ijk_self = arrays.Basis(transportFrames[origin_id]) jVector = arrays.ColumnVector(jVector).hat projected = jVector.project_to_plane(ijk_self[:, -1]) j_new = math.normalize( projected.change_reference_frame(ijk_self)).squeeze() z_new = np.array([0, 0, 1]) ijk_new = arrays.Basis( math.normalize(math.cross(j_new, z_new)), j_new, z_new ) newTransportFrames = np.zeros_like(transportFrames) for i, frame in enumerate(transportFrames): newTransportFrames[i] = arrays.Basis(frame @ ijk_new) if return_index: return newTransportFrames, origin_id else: return newTransportFrames
def cross(self, vector: np.ndarray) -> np.ndarray: """ """ return math.cross(self, vector)
def argSortByBasis(array, ref_basis, n_to_check=20): """arg_basis_sort [summary] For an ndarray describing the points along a closed contour and a ref_basis which describes the plane outpud the ids of the sorted points. The points are sorted such that the ndarray[0,:] is the point closest to the i-axis and the orientation of rotation is determined by the closest point Args: ndarray (_np.ndarray) : N x M matrix where N is the number of points and M is the total number of dimensions ref_basis (_np.ndarray): 3 x 3 basis matrix discribing return_ref (bool, optional): return a copy of ndarray in the ref_basis frame. Defaults to True. Returns: _np.ndarray: list of sorted indices """ meanLocation = np.mean(array, axis=-1, keepdims=True) ndarray_centered = array - meanLocation n_pts = ndarray_centered.shape[-1] # ndarray_centered_2d A = ref_basis.T @ ndarray_centered ids_vector = np.arange(n_pts)[None, :] # concatenate A with id vector A_concat = np.concatenate([A, ids_vector], axis=0) # initialize a vectore to store the sorted sorted_ids = np.zeros(A_concat.shape[-1]) # reference_basis_2d ijk = np.identity(3) # project A to the i direction project_to_x = math.scalar_project(A, ijk[:, 0, None]) # ids of points moving in the positive direction to_use_ids = np.where(project_to_x > 0)[0] # subsample ndarray_centered_2d_concat_with_ids subset = A_concat[:, to_use_ids] # project the subset values to j project_to_y = math.scalar_project(subset[0:-1, :], ijk[1, :]) # locate the key of the point which is closest to the x axis of the subset id_of_subset = np.argmin(np.abs(project_to_y)) # get the id of the starting point start_id = int(subset[-1, id_of_subset]) # store the starting point in the initialesd vector sorted_ids[0] = start_id # create a copy of the current point current_pt = A_concat[0:-1, start_id, None].copy() # delete this point from the ndarray_centered_2d concated with an id vector copy_A_cont = np.delete(A_concat, start_id, axis=-1) counter = 0 while copy_A_cont.shape[-1] > 0: if copy_A_cont.shape[-1]: closest_ind = np.argmin( np.linalg.norm(copy_A_cont[0:-1] - current_pt, axis=0)) counter += 1 assert counter < n_pts*2, \ 'too many iterations something is wrong with the code' current_pt = copy_A_cont[0:-1, closest_ind, None] sorted_ids[counter] = int(copy_A_cont[-1, closest_ind]) copy_A_cont = np.delete(copy_A_cont, closest_ind, axis=-1) sorted_ndarray_in_ref = A[:, sorted_ids.astype(int)] # check if clockwise check = 0 base_vector = math.normalize(sorted_ndarray_in_ref[:, 0, None]) for i in list(range(n_to_check)): test_vector = math.normalize(sorted_ndarray_in_ref[:, i, None]) check += math.cross(base_vector, test_vector)[-1] # if not rotating clockwise then flip order so that # points rotate in a clockwise direction if check < 0: sorted_ids = np.flipud(sorted_ids) sorted_ids = np.roll(sorted_ids, 1) return np.array([int(i) for i in sorted_ids])
def calc_basis(self): i = math.normalize(self[:, 0, None] - self.centroid).squeeze() k = self.calc_normal() j = math.normalize(math.cross(k, i)) return arrays.Basis(i.squeeze(), j.squeeze(), k.squeeze())