def contained_circle_aq(poly): """ The contained circle areal quotient is defined by the ratio of the area of the largest contained circle and the shape itself. """ pointset = _get_pointset(poly) radius, (cx, cy) = _mcc(pointset) return poly.area / (_PI * radius ** 2)
def flaherty_crumplin_radius(poly): """ The Flaherty & Crumplin (1992) index, OS_3 in Altman's thesis. The ratio of the radius of the equi-areal circle to the radius of the MBC """ pointset = _get_pointset(poly) r_eac = np.sqrt(poly.area/_PI) r_mbc, _ = _mbc(pointset) return r_eac / r_mbc
def reock(poly): """ The Reock compactness measure, defined by the ratio of areas between the minimum bounding/containing circle of a shape and the shape itself. Measure A1 in Altman's thesis, cited for Frolov (1974), but earlier from Reock (1963) """ pointset = _get_pointset(poly) radius, (cx, cy) = _mbc(pointset) return poly.area / (_PI * radius ** 2)
def eig_seitzinger(poly): """ The Eig & Seitzinger (1981) shape measure, defined as: L - W Where L is the maximal east-west extent and W is the maximal north-south extent. Defined as measure LW_5 in Altman's thesis """ ptset = _get_pointset(poly) xs, ys = [p[0] for p in ptset], [p[1] for p in ptset] l = np.max(xs) - np.min(xs) w = np.max(ys) - np.min(ys) return l - w
def moment_of_inertia(poly, dmetric=_dst.euclidean): """ Computes the moment of inertia of the poly. This treats each boundary point as a point-mass of 1. Thus, for constant unit mass at each boundary point, the MoI of this pointcloud is \sum_i d_{i,c}^2 where c is the centroid of the poly Altman's OS_1 measure, cited in Boyce and Clark (1964), also used in Weaver and Hess (1963). """ pointset = _get_pointset(poly) dists = [dmetric(pt, poly.centroid)**2 for pt in pointset] return poly.area / np.sqrt(2 * np.sum(dists))
def minimum_bounding_circle(points): """ Implements Skyum (1990)'s algorithm for the minimum bounding circle in R^2. 0. Store points clockwise. 1. Find p in S that maximizes angle(prec(p), p, succ(p) THEN radius(prec(p), p, succ(p)). This is also called the lexicographic maximum, and is the last entry of a list of (radius, angle) in lexicographical order. 2a. If angle(prec(p), p, succ(p)) <= 90 degrees, then finish. 2b. If not, remove p from set. """ was_polygon = not isinstance(points, (np.ndarray,list)) if was_polygon: from .compactness import _get_pointset points = _get_pointset(points) chull = ConvexHull(points) points = np.asarray(points)[chull.vertices] points = points[::-1] #shift from ccw to cw points = list(map(tuple, points)) POINTS = copy.deepcopy(points) removed = [] i=0 while True: triple = _nples(points) angles = [_angle(*next(triple)) for p in points] circles = [_circle(*next(triple)) for p in points] radii = [np.max(c[0]) for c in circles] lexord = np.lexsort((angles, radii))#really weird defaults lexmax = lexord[-1] #recall, we're addressing p, previous_p, two_before_p #recall the triple generator is in leading-index order. candidate = points[lexmax], points[lexmax-1], points[lexmax-2] if angles[lexmax] > PI/2: removed = points.pop(lexmax-1) else: radius, center = circles[lexmax] if was_polygon: from shapely import geometry return geometry.Point(tuple(center)).buffer(radius) return circles[lexmax] i+=1
def pairwise_lw(chain): """ Construct the diameter and width of a polygon, as defined as the longest and shortest pairwise distances between a polygon's vertices. Returns -------- Returns the indices of all minima/maxima pairs, as well as their values. That is, if two points are minimal with distance d and three pairs are maximal with distance D, this would return: ((p1, p2), d, (p1, p2, p3), d) Thus, you need to be careful with automated unpacking. """ ptset = _get_pointset(chain) pwds = d.pdist(ptset) sqf = d.squareform(pwds) minval = pwds[np.nonzero(pwds)].min() #have to account for zero selfdist amin, amax = np.where(sqf == minval), np.where(sqf == pwds.max()) return amin, sqf[amin], amax, sqf[amax]
#Warn('angle close to zero') radii = dist.euclidean(A,B)/2. center_x = float(Ax + Bx)/2. center_y = float(Ay + By)/2. else: try: D = 2*(Ax*(By - Cy) + Bx*(Cy - Ay) + Cx*(Ay - By)) center_x = float(((Ax**2 + Ay**2)*(By-Cy) + (Bx**2 + By**2)*(Cy-Ay) + (Cx**2 + Cy**2)*(Ay-By)) / D) center_y = float(((Ax**2 + Ay**2)*(Cx-Bx) + (Bx**2 + By**2)*(Ax-Cx) + (Cx**2 + Cy**2)*(Bx-Ax)) / D) radii = np.max([dmetric((center_x, center_y), pt) for pt in [A,B,C]]) except dec.InvalidOperation: center_x = center_y = radii = -np.inf return radii, (center_x, center_y) if __name__ == '__main__': import libpysal from libpysal.weights._contW_lists import _get_verts as _get_pointset import geopandas df = geopandas.read_file(libpysal.examples.get_path('columbus.shp')) ix = np.random.randint(0,len(df.geometry)) #ix = 5 ptset = _get_pointset(df.geometry[ix]) _mbc_animation(ptset, plotname='test', buffer_=.66) print(ix)