def convex_hull_inflation(ch: ss.ConvexHull, inflation_ratio: float = 0.2, vertices_only: bool = True) -> ss.ConvexHull: """ TODO: consider the choice of "center_of_mass" Parameters ---------- to write Returns ------- to write """ ch_vertices = ch.points[ch.vertices] center_of_mass = np.mean(ch.points, axis=0) ch_vertices = ch_vertices - center_of_mass # relative coord. ch_vertices = ch_vertices * (1 + inflation_ratio) ch_vertices = ch_vertices + center_of_mass if vertices_only: inflated_ch = ss.ConvexHull(ch_vertices) else: inflated_ch = ss.ConvexHull(ch_vertices, incremental=True) inflated_ch.add_points(ch.points[is_in_hull(ch.points, inflated_ch)]) inflated_ch.close() return inflated_ch
def plot(self, axis=-1, coords=[], label="", **kwargs): """ Plots the polytope on the given axis. """ if self.isLowerDimensional() or self.isEmpty(): # Will not plot empty or lower-dimensional polytopes return num_coords = len(coords) if num_coords > 1 and num_coords <= 3: vertices = self.project(coords) if num_coords == 1 or num_coords > 3: raise AssertionError("Cannot plot projection onto more than 3 " "dimensions or onto 1 dimension") if self.n > 3 and num_coords == 0: raise AssertionError("Cannot plot higher dimensional polytope than" "3D") no_axis = axis == -1 if no_axis: # Axis not passed in, create a new figure fig = plt.figure() if self.n == 2 or num_coords == 2: axis = fig.add_subplot(111) if self.n == 3 or num_coords == 3: axis = fig.add_subplot(111, projection='3d') # TODO plotting for self.n == 1 if self.n == 2 or num_coords == 2: # 2D plot if num_coords == 0: # The polytope is 2D and we plot it as such vertices = self.vrep(return_as_matrix=True) co = ss.ConvexHull(vertices) # Filled region axis.fill(vertices[co.vertices, 0], vertices[co.vertices, 1], label=label, **kwargs) if self.n == 3 or num_coords == 3: # 3D plot if num_coords == 0: # The polytope is 3D and we plot is as such vertices = self.vrep(return_as_matrix=True) co = ss.ConvexHull(vertices) tri = matplotlib.tri.Triangulation(vertices[:, 0], vertices[:, 1], triangles=co.simplices) axis.plot_trisurf(vertices[:, 0], vertices[:, 1], vertices[:, 2], triangles=tri.triangles, **kwargs) if no_axis: plt.show()
def get_orientation_features(mask): if type(mask) == sitk.SimpleITK.Image: mask = sitk.GetArrayFromImage(mask) # Get nonzero point indices if convex hull for memory reduction data = np.transpose(np.nonzero(mask)) try: points = sp.ConvexHull(data).points success = False while not success: try: center, radii, evecs, v = of.ellipsoid_fit(points) success = True except np.linalg.linalg.LinAlgError: print( "Encountered singular matrix, segmentation too small, dilating." ) elem = morphology.ball(2) mask = morphology.binary_dilation(mask, elem) data = np.transpose(np.nonzero(mask)) points = sp.ConvexHull(data).points points = of.data_regularize(points, divs=8) # Convert evecs to angles X = evecs[:, 0] Y = evecs[:, 1] Z = evecs[:, 2] alpha = np.arctan2(Z[0], Z[1]) beta = np.arccos(Z[2]) gamma = np.arctan2(X[2], Y[2]) except sp.qhull.QhullError: # TODO: 2D ellipse fit alpha = 0 beta = 0 gamma = 0 panda_labels = ['of_theta_x', 'of_theta_y', 'of_theta_z'] orientation_features = [alpha, beta, gamma] panda_dict = dict(zip(panda_labels, orientation_features)) orientation_dict = dict() orientation_dict['all'] = pd.Series(panda_dict) orientation_features = pd.Series(orientation_dict) return orientation_features
def generate_image_and_stats(data, cluster_coords, regions_image, optional_params, axes): """Adds cluster shape to shapes image and also returns regionprops of that shape""" one_region_image = np.zeros((data["dimensions"][0], data["dimensions"][1]), np.uint8) concave_hull = alphashape.alphashape(cluster_coords) border_points = concave_hull.exterior.coords list_array = [] for coord in border_points: list_array.append(coord) # border_points = cluster_coords[spatial.ConvexHull(cluster_coords).vertices] hull = spatial.ConvexHull(cluster_coords) border_points = np.array(list_array, dtype='int32') regions_image = cv2.fillPoly(regions_image, np.int32([border_points]), (255, 255, 255)) one_region_image = cv2.fillPoly(one_region_image, np.int32([border_points]), 255) labeled_image = label(one_region_image, background=0) properties = regionprops(labeled_image) degrees = math.degrees(properties[0].orientation) parameters = ((properties[0].centroid[1], properties[0].centroid[0]), (int(properties[0].major_axis_length), int(properties[0].minor_axis_length)), float(degrees)) regions_image = cv2.ellipse(regions_image, parameters, (0, 0, 255)) add_outline(border_points, axes, optional_params, properties) ellipticity = compute_ellipticity_area_based(data, border_points) return regions_image, properties, ellipticity, hull.area, hull.volume
def get_hulls(exp, ts): hulls = [] for t in ts: nx_graph = exp.nx_graph[t] threshold = 0.1 S = [ nx_graph.subgraph(c).copy() for c in nx.connected_components(nx_graph) ] selected = [ g for g in S if g.size(weight="weight") * len(g.nodes) / 10**6 >= threshold ] polys = Polygon() if len(selected) >= 0: area_max = 0 for g in selected: nodes = np.array([ node.pos(t) for node in exp.nodes if node.is_in(t) and np.all(is_in_study_zone(node, t, 1000, 150)) and ( node.label in g.nodes) ]) if len(nodes) > 3: hull = spatial.ConvexHull(nodes) poly = Polygon( [nodes[vertice] for vertice in hull.vertices]) area_hull = poly.area * 1.725**2 / (1000**2) polys = polys.union(poly) print(t, len(selected), polys.area) hulls.append(polys) return hulls
def planar_hull(points, normal, origin=None, input_convex=False): ''' Find the convex outline of a set of points projected to a plane. Arguments ----------- points: (n,3) float, input points normal: (3) float vector, normal vector of plane origin: (3) float, location of plane origin input_convex: bool, if True we assume the input points are already from a convex hull which provides a speedup. Returns ----------- hull_lines: (n,2,2) set of unordered line segments T: (4,4) float, transformation matrix ''' from .points import project_to_plane if origin is None: origin = np.zeros(3) if not input_convex: pass planar, T = project_to_plane(points, plane_normal=normal, plane_origin=origin, return_planar=False, return_transform=True) hull_edges = spatial.ConvexHull(planar[:, 0:2]).simplices hull_lines = planar[hull_edges] planar_z = planar[:, 2] height = np.array([planar_z.min(), planar_z.max()]) return hull_lines, T, height
def __init__(self, list_hulls, name="unnamed", mask=None, check_mask_outofbounds=True): """ Initializes a bounding convex hull around a list of bounding convex hulls or series of points. A unity-weighted mask is computed for the region that falls within this convex hull if a mask of (y, x) coordinates is not provided. Otherwise if a mask is provided and the check_mask_outofbounds value is set the masked coordinates are not verified to fall within the hull. The latter should thus be used with some caution by the user, but can potentially significantly speed up the mask creation process for axis aligned regions. """ self._name = name self._check_mask_outofbounds = check_mask_outofbounds self._cached_filled_mask = None self._vertices = points = np.vstack([ b.corners if hasattr(b, "corners") else [b[0], b[1]] for b in list_hulls ]) self._hull = spat.ConvexHull(points) if mask is None: self._mask, self._mask_weights = self.init_mask() else: self.sparse_mask = mask
def max_dist(point_list): """ Find the maximum distance between two points in a point list using convex hull. """ # Find the convex hull of the point set conv_hull = spatial.ConvexHull(point_list) # Find the vertices on the convex hull vertices = np.vstack(point_list[conv_hull.vertices]) # Find the pairwise distances dists = spatial.distance.pdist(vertices) dists = spatial.distance.squareform(dists) # Find the indices of the furthest points idx = np.unravel_index(np.argmax(dists), dists.shape) idx = list(idx) idx1, idx2 = conv_hull.vertices[idx] p1, p2 = vertices[idx] print('The furthest points are:') print('Index: {}, coordinates: {}'.format(idx1, tuple(p1))) print('Index: {}, coordinates: {}'.format(idx2, tuple(p2))) return np.max(dists)
def get_pareto_frontier(pts): """ Iteratively filter points based on the convex hull heuristic """ pareto_groups = [] # loop while there are points remaining while pts.shape[0]: # brute force if there are few points: if pts.shape[0] < 10: pareto_groups.append(get_pareto_undominated_by(pts)) break # compute vertices of the convex hull hull_vertices = spatial.ConvexHull(pts).vertices # get corresponding points hull_pts = pts[hull_vertices] # get points in pts that are not convex hull vertices nonhull_mask = np.ones(pts.shape[0], dtype=bool) nonhull_mask[hull_vertices] = False pts = pts[nonhull_mask] # get points in the convex hull that are on the Pareto frontier pareto = get_pareto_undominated_by(hull_pts) pareto_groups.append(pareto) # filter remaining points to keep those not dominated by # Pareto points of the convex hull pts = get_pareto_undominated_by(pts, pareto) return np.vstack(pareto_groups)
def find_vectors_in_matrix(data, graph: bool = False, file_name: str = ""): """ Finds and returns vectors in a 2D matrix """ labeled_array, num_features = label( data, structure=[[1, 1, 1], [1, 1, 1], [1, 1, 1]] ) # group and label print(f"Group count: {config.CC_OKCYAN}%d{config.CC_ENDC}" % num_features) if graph: np.savetxt(fna(file_name, "matrix_labeled", "txt"), labeled_array, fmt="%d") vectors = [] for i in range(num_features): index = i + 1 indices = np.argwhere(labeled_array == index) # find the group if len(indices) < THRESHOLD: # not an important line if under threshold continue candidates = indices[spatial.ConvexHull(indices).vertices] # convex hull dist_mat = spatial.distance_matrix(candidates, candidates) # distance btw points = np.unravel_index(dist_mat.argmax(), dist_mat.shape) # furthest cands vectors.append( [ candidates[points[0]][1], candidates[points[0]][0], candidates[points[1]][1], candidates[points[1]][0], ] ) print(f"Vector count: {config.CC_OKCYAN}%d{config.CC_ENDC}" % len(vectors)) return np.array(vectors)
def InROI(file, Coordinates, TMin, TMax): from matplotlib import path import numpy as np from scipy import spatial as sp K = sp.ConvexHull(Coordinates).vertices K = np.append(K, K[0]) XVert = Coordinates[K, 0] YVert = Coordinates[K, 1] XY = np.stack((XVert, YVert), axis=1) data_in = [0] * len(file['T']) data_out = [0] * len(file['T']) for i in range(len(file['X'])): # is it in the prescribed interval if i >= TMin and i <= TMax: p = path.Path(XY) if p.contains_points([(file['X'][i], file['Y'][i])]): data_in[i] = 1 else: data_out[i] = 1 for i, number in enumerate(data_in): data_in[i] = number > 0 for i, number in enumerate(data_out): data_out[i] = number > 0 return data_in, data_out
def plot(self, dim_proj=[0,1], largest_ball=False, **kwargs): """ Plots a 2d projection of the polytope. INPUTS: dim_proj: dimensions in which to project the polytope """ if self.empty: print('Cannot plot empty polytope') return if len(dim_proj) != 2: raise ValueError('Only 2d polytopes!') # extract vertices components vertices_proj = np.hstack(self.vertices).T[:,dim_proj] hull = spatial.ConvexHull(vertices_proj) verts = [hull.points[i].tolist() for i in hull.vertices] verts += [verts[0]] codes = [Path.MOVETO] + [Path.LINETO]*(len(verts)-2) + [Path.CLOSEPOLY] path = Path(verts, codes) ax = plt.gca() patch = patches.PathPatch(path, **kwargs) ax.add_patch(patch) plt.xlabel(r'$x_' + str(dim_proj[0]+1) + '$') plt.ylabel(r'$x_' + str(dim_proj[1]+1) + '$') ax.autoscale_view() if largest_ball: circle = plt.Circle((self.center[0], self.center[1]), self.radius, facecolor='white', edgecolor='black') ax.add_artist(circle) return
def orthogonal_projection(self, residual_variables, method='convex_hull'): if method == 'convex_hull': A_proj, b_proj, v_proj = orthogonal_projection_CHM(self.lhs_min, self.rhs_min, residual_variables) p_proj = Polytope(A_proj, b_proj) p_proj.assemble(redundant=False, vertices=v_proj) # elif method == 'block_elimination': # drop_variables = [i+1 for i in range(self.n_variables) if i not in residual_variables] # M = np.hstack((self.rhs_min, -self.lhs_min)) # M = cdd.Matrix([list(m) for m in M]) # M.rep_type = cdd.RepType.INEQUALITY # M_proj = M.block_elimination(drop_variables) # M_proj.canonicalize() # A_proj = - np.array([list(M_proj[i])[1:] for i in range(M_proj.row_size)]) # b_proj = np.array([list(M_proj[i])[:1] for i in range(M_proj.row_size)]) # p_proj = Polytope(A_proj, b_proj) # p_proj.assemble() elif method == 'vertex_enumeration': v_proj = np.hstack(self.vertices).T[:,residual_variables] if len(residual_variables) > 1: hull = spatial.ConvexHull(v_proj) A_proj = np.array(hull.equations)[:, :-1] b_proj = - np.array(hull.equations)[:, -1:] else: A_proj = np.array([[1.],[-1.]]) b_proj = np.array([[max(v_proj)[0]],[-min(v_proj)[0]]]) p_proj = Polytope(A_proj, b_proj) p_proj.assemble() return p_proj
def compute_empirical_nodal_width(self, mode='mean') -> float: r""" Compute the set's nodal width. """ cvx_hull = sp.ConvexHull(self.vec.transpose()) cols = np.roll(cvx_hull.simplices, shift=1, axis=-1).reshape(-1) rows = cvx_hull.simplices.reshape(-1) # Form sparse coo_matrix from extracted pairs affinity_matrix = sparse.coo_matrix((cols * 0 + 1, (rows, cols)), shape=(cvx_hull.points.shape[0], cvx_hull.points.shape[0])) # Symmetrize the matrix to obtain an undirected graph. extended_row = np.concatenate([affinity_matrix.row, affinity_matrix.col]) extended_col = np.concatenate([affinity_matrix.col, affinity_matrix.row]) affinity_matrix.row = extended_row affinity_matrix.col = extended_col affinity_matrix.data = np.concatenate([affinity_matrix.data, affinity_matrix.data]) affinity_matrix = affinity_matrix.tocsr().tocoo() # Delete potential duplicate pairs distance = np.linalg.norm(cvx_hull.points[affinity_matrix.row, :] - cvx_hull.points[affinity_matrix.col, :], axis=-1) if mode is 'mean': nodal_distance = np.mean(distance) # average distance to neighbors elif mode is 'max': nodal_distance = np.max(distance) elif mode is 'median': nodal_distance = np.median(distance) else: raise TypeError("Parameter mode must be one of ['mean', 'max', 'median']") return nodal_distance
def crown_from_points(pts): if len(pts) > 3: hull = spatial.ConvexHull(np.stack(pts)) return hull.simplices, np.array( [[hull.points[f[0]], hull.points[f[1]], hull.points[f[2]]] for f in hull.simplices])
def _prepare_hull(coordinates, hull): """ Construct a hull from the coordinates given a hull type Will either return: - a bounding box array of [xmin, ymin, xmax, ymax] - a scipy.spatial.ConvexHull object from the Qhull library - a shapely shape using alpha_shape_auto """ if isinstance(hull, numpy.ndarray): assert len( hull ) == 4, f"bounding box provided is not shaped correctly! {hull}" assert hull.ndim == 1, f"bounding box provided is not shaped correctly! {hull}" return hull if (hull is None) or (hull == "bbox"): return _bbox(coordinates) if HAS_SHAPELY: # protect the isinstance check if import has failed if isinstance(hull, (_ShapelyPolygon, _ShapelyMultiPolygon)): return hull if HAS_PYGEOS: if isinstance(hull, pygeos.Geometry): return hull if isinstance(hull, str): if hull.startswith("convex"): return spatial.ConvexHull(coordinates) elif hull.startswith("alpha") or hull.startswith("α"): return alpha_shape_auto(coordinates) elif isinstance(hull, spatial.qhull.ConvexHull): return hull raise ValueError(f"Hull type {hull} not in the set of valid options:" f" (None, 'bbox', 'convex', 'alpha', 'α', " f" shapely.geometry.Polygon, pygeos.Geometry)")
def make(self, key): density = 110000 # per cubic mm xyz = np.stack((design.Geometry.EPixel() & key).fetch('e_loc')) margin = 75 bounds_min = xyz.min(axis=0) - margin bounds_max = xyz.max(axis=0) + margin volume = (bounds_max - bounds_min).prod() * 1e-9 npoints = int(volume * density + 0.5) # generate random points that aren't too close min_distance = 10.0 # cells aren't not allowed any closer points = np.empty((npoints, 3), dtype='float32') replace = np.r_[:npoints] while replace.size: points[replace, :] = np.random.rand(replace.size, 3) * (bounds_max - bounds_min) + bounds_min replace = spatial.cKDTree(points).query_pairs(min_distance, output_type='ndarray')[:, 0] # eliminate points that are too distant inner = (spatial.Delaunay(xyz).find_simplex(points)) != -1 d, _ = spatial.cKDTree(points[inner, :]).query(points[~inner, :], distance_upper_bound=margin) points = np.vstack((points[inner, :], points[~inner, :][d < margin, :])) self.insert1(dict( key, margin=margin, density=density, npoints=points.shape[0], min_distance=min_distance, points=points, volume=spatial.ConvexHull(points).volume * 1e-9, inner_count=inner.sum()))
def find_footprint(self, points): """This function will take in an numpy.array of points in 2D and create a convex polygon that encapsilates every point provided.\ Arguments to pass in: points = 2D array of points numpy.array([:,:]) Returns a Polygon""" footprint = Polygon() if self.halo_density: buffed_points = self.halo_buffer(points, self.halo_radius, self.halo_density) else: buffed_points = points if not points.size: pass else: hull = spatial.ConvexHull(buffed_points) for vertex in hull.vertices: point = Point32() point.x = buffed_points[vertex, 0] point.y = buffed_points[vertex, 1] point.z = 0.0 footprint.points.append(point) return footprint
def overlap(rec1, rec2): if not collisionCheck(rec1, rec2): return 0. x1, y1, theta1, l1, w1 = rec1 x2, y2, theta2, l2, w2 = rec2 cos1 = np.cos(theta1) sin1 = np.sin(theta1) diffx = x2 - x1 diffy = y2 - y1 x2 = diffx * cos1 + diffy * sin1 y2 = -diffx * sin1 + diffy * cos1 cos2 = np.cos(theta2 - theta1) sin2 = np.sin(theta2 - theta1) A = np.array([[1, 0, 1], [-1, 0, 1], [0, 1, 1], [0, -1, 1], [cos2, sin2, 1], [-cos2, -sin2, 1], [-sin2, cos2, 1], [sin2, -cos2, 1]]) b = np.array([ l1, l1, w1, w1, l2 + cos2 * x2 + sin2 * y2, l2 - cos2 * x2 - sin2 * y2, w2 - sin2 * x2 + cos2 * y2, w2 + sin2 * x2 - cos2 * y2 ]) res = linprog(np.array([0, 0, -1]), A_ub=A, b_ub=b, bounds=(-np.inf, np.inf)) assert res.success interior = res.x[:2] halfspaces = np.append(A[:, :2], -b[:, None], axis=1) hs = spspatial.HalfspaceIntersection(halfspaces, interior).intersections return spspatial.ConvexHull(hs).volume
def plot_points(data, fig=None, ax=None, inp_color=None): # Takes as input all the points if fig is None: fig = plt.figure() # If no plot is defined ax = fig.gca(projection='3d') for i in range(len(data)): points = np.asarray(data[i]) hull = sp.ConvexHull(points) # Plotting the points with scatter if not inp_color: ax.plot_trisurf(points[:, 0], points[:, 1], points[:, 2], triangles=hull.simplices, color='b') else: ax.plot_trisurf(points[:, 0], points[:, 1], points[:, 2], triangles=hull.simplices, color=inp_color) # Checking if there are a prismatic joint that needs to be denoted # Label the axis ax.set_xlabel('X'), ax.set_ylabel('Y'), ax.set_zlabel('Z') ax.set_xlim([-2, 5]), ax.set_ylim([-2.5, 1]), ax.set_zlim([-1, 1]) plt.savefig("test.png") plt.show() return (fig, ax)
def hull_points(obj, qhull_options='QbB Pp'): """ Try to extract a convex set of points from multiple input formats. Parameters --------- obj: Trimesh object (n,d) points (m,) Trimesh objects Returns -------- points: (o,d) convex set of points """ if hasattr(obj, 'convex_hull'): return obj.convex_hull.vertices initial = np.asanyarray(obj, dtype=np.float64) if len(initial.shape) != 2: raise ValueError('points must be (n, dimension)!') hull = spatial.ConvexHull(initial, qhull_options=qhull_options) points = hull.points[hull.vertices] return points
def get_convex_hull(locations): array = [] for i in locations: array.append([i.x, i.y]) hullArray = np.array(array) hull = sp.ConvexHull(hullArray) return hull.volume
def RandPolytope(n, m): import scipy.spatial as sp import random # Hyperspheroid coordinates take the form # x_1 = r*cos(t_1) # x_2 = r*sin(t_1)*cos(t_2) # x_3 = r*sin(t_1)*sin(t_2)*cos(t_3) # ... # x_n = r*sin(t_1)*...*sin(t_n-1)*cos(t_n) r = random.uniform(1.0, 10.0) arr = [] for i in range(m): angles = [np.deg2rad(random.randint(1, 360)) for a in range(n - 1)] arr.append(nsphere_to_cartesian(r, angles)) #arr.append([random.uniform(0.0,50.0) for a in range(n)]) # For now we just have the point (0) as our guaranteed point arr.append(np.array([0 for a in range(n)])) hull = sp.ConvexHull(arr) A = hull.equations[:, 0:-1] b = hull.equations[:, -1] #return A, b return hull.points
def _bresenham(self, faces, dx): r''' A Bresenham line function to generate points to fill in for the fibers ''' line_points = [] for face in faces: # Get in hull order fx = face[:, 0] fy = face[:, 1] fz = face[:, 2] # Find the axis with the smallest spread and remove it to make 2D if (np.std(fx) < np.std(fy)) and (np.std(fx) < np.std(fz)): f2d = np.vstack((fy, fz)).T elif (np.std(fy) < np.std(fx)) and (np.std(fy) < np.std(fz)): f2d = np.vstack((fx, fz)).T else: f2d = np.vstack((fx, fy)).T hull = sptl.ConvexHull(f2d, qhull_options='QJ Pp') face = np.around(face[hull.vertices].astype(float), 6) for i in range(len(face)): vec = face[i] - face[i - 1] vec_length = np.linalg.norm(vec) increments = np.ceil(vec_length / dx) check_p_old = np.array([-1, -1, -1]) for x in np.linspace(0, 1, increments): check_p_new = face[i - 1] + (vec * x) if np.sum(check_p_new - check_p_old) != 0: line_points.append(check_p_new) check_p_old = check_p_new return np.asarray(line_points)
def planar_hull(points, normal, origin=None): """ Find the convex outline of a set of points projected to a plane. Parameters ----------- points: (n,3) float, input points normal: (3) float vector, normal vector of plane origin: (3) float, location of plane origin Returns ----------- hull_lines: (n,2,2) set of unordered line segments T: (4,4) float, transformation matrix height: (2,) float, [Z min, Z max] """ from .points import project_to_plane if origin is None: origin = np.zeros(3) planar, T = project_to_plane(points, plane_normal=normal, plane_origin=origin, return_planar=False, return_transform=True) hull_edges = spatial.ConvexHull(planar[:, 0:2]).simplices hull_lines = planar[hull_edges] planar_z = planar[:, 2] height = np.array([planar_z.min(), planar_z.max()]) return hull_lines, T, height
def compute_cell_diameter(self) -> float: cell_mask = self.get_cell_mask() cell_mask_points = np.argwhere(cell_mask == 1) convex_hull = spatial.ConvexHull(cell_mask_points) boundary_points = cell_mask_points[convex_hull.vertices] d = np.max(pairwise_distances(boundary_points)) return d
def hull_points(obj): ''' Try to extract a convex set of points from multiple input formats. Arguments --------- obj: Trimesh object (n,d) points (m,) Trimesh objects Returns -------- points: (o,d) convex set of points ''' if hasattr(obj, 'convex_hull'): points = obj.convex_hull.vertices elif util.is_sequence(obj): initial = np.asanyarray(obj) if len(initial.shape) != 2: raise ValueError('Points must be (n, dimension)!') hull = spatial.ConvexHull(initial, qhull_options='QbB Pp') points = hull.points[hull.vertices] else: raise ValueError('Can\'t extract hull points from %s', obj.__class__.__name__) return points
def _export_vor_fibres(self): r""" Run through the throat vertices, compute the convex hull order and save the vertices and ordered faces in a pickle dictionary to be used in blender """ import pickle as pickle Indices = [] for t in self.throats(): indices = list(self["throat.vert_index"][t].keys()) verts = self._vor.vertices[indices] # Need to order the indices in convex hull order # Compute the standard deviation in all coordinates and eliminate # the axis with the smallest to make 2d stds = [ np.std(verts[:, 0]), np.std(verts[:, 1]), np.std(verts[:, 2]) ] if np.argmin(stds) == 0: verts2d = np.vstack((verts[:, 1], verts[:, 2])).T elif np.argmin(stds) == 1: verts2d = np.vstack((verts[:, 0], verts[:, 2])).T else: verts2d = np.vstack((verts[:, 0], verts[:, 1])).T # 2d convexhull returns vertices in hull order hull2d = sptl.ConvexHull(verts2d, qhull_options='QJ Pp') # Re-order the vertices and save as list (blender likes them as lists) Indices.append(np.asarray(indices)[hull2d.vertices].tolist()) # Create dictionary to pickle data = {} data["Verts"] = self._vor.vertices data["Indices"] = Indices pickle.dump(data, open("fibres.p", "wb"))
def hull(x, T, data): # getting minimal G for each x - solution phases Fgy = [fase.G(x, T) for fase in data if fase.kind == 'sol'] Gmin = np.amin(Fgy, axis=0) Gmin = np.column_stack((x, Gmin)) # adding stoichiometric phases for fase in data: if fase.kind == 'stq': point = [[fase.xB, fase.G(T)]] Gmin = np.append(Gmin, point, axis=0) # ordering array by composition Gmin = Gmin[np.argsort(Gmin[:, 0])] # getting convex hull for solution phases hull = spa.ConvexHull(Gmin) # shifting first position to end vertices = np.roll(hull.vertices, -1) # separating points belonging to hull points = hull.points[vertices, :] return Gmin, points, vertices
def find_ball(mask): contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) if contours: contour = max(contours, key=cv2.contourArea) if cv2.contourArea(contour) > BALL_MIN_AREA: test = np.array(contour.reshape(-1, 2)) # two points which are fruthest apart will occur as vertices of the convex hull candidates = test[spatial.ConvexHull(test).vertices] # get distances between each pair of candidate points dist_mat = spatial.distance_matrix(candidates, candidates) # get indices of candidates that are furthest apart i, j = np.unravel_index(dist_mat.argmax(), dist_mat.shape) p1, p2 = candidates[i], candidates[j] delta_x = abs((p1[0] - p2[0]) / 2) delta_y = abs((p1[1] - p2[1]) / 2) x = int(min(p1[0], p2[0]) + delta_x) y = int(min(p1[1], p2[1]) + delta_y) dist = int(math.sqrt((x - p1[0])**2 + (y - p1[1])**2)) return (x, y), dist return (0, 0), 0