def _normalize(p1, p2, p3): """ Return feature parts for a trio of points - re-ordered points, ratio, theta. """ h12 = _hypot(p2.x - p1.x, p2.y - p1.y) h13 = _hypot(p3.x - p1.x, p3.y - p1.y) h23 = _hypot(p3.x - p2.x, p3.y - p2.y) hs = sorted([h12, h13, h23], reverse=True) # # Shuffle the points into correct order. # if hs[0] is h12: if hs[1] is h13: p1, p2, p3 = p1, p2, p3 elif hs[1] is h23: p1, p2, p3 = p2, p1, p3 elif hs[0] is h13: if hs[1] is h12: p1, p2, p3 = p1, p3, p2 elif hs[1] is h23: p1, p2, p3 = p3, p1, p2 elif hs[0] is h23: if hs[1] is h12: p1, p2, p3 = p2, p3, p1 elif hs[1] is h13: p1, p2, p3 = p3, p2, p1 h, ratio, theta = _measure(p1, p2, p3) return p1, p2, p3, ratio, theta
def _measure(p1, p2, p3): """ Return hypotenuse, ratio and theta for a trio of ordered points. """ ha, hb = _hypot(p3.x - p1.x, p3.y - p1.y), _hypot(p2.x - p1.x, p2.y - p1.y) va, vb = Vector(p1, p2), Vector(p1, p3) theta = _atan2(va.y, va.x) x = vb.x * _cos(-theta) - vb.y * _sin(-theta) y = vb.x * _sin(-theta) + vb.y * _cos(-theta) ratio = ha / hb theta = _atan2(y, x) return hb, ratio, theta
def rotate3d( point: Iterable[float], angle: float, axis: Iterable[float] = (0.0, 0.0, 1.0), rounding: int = -1, degrees: bool = True) -> Tuple[float]: """ Rotate a point around an axis. Take a point in 3d space represented as a tuple or list of three (3) values and rotate it by an angle around a given axis vector. Parameters: point: The point to rotate. The format for the coordinates is ``(x, y, z)``. angle: The angle of rotation. By default, angle is set to be input in degrees. See the **degrees** parameter if you want to use radians instead. axis: The axis to rotate the point around. By default, this is the z-axis ``(0, 0, 1)``. rounding: The number of decimal points the result will be rounded to. Default value is -1, which does not round the end result. degrees: When set to ``True``, this function interprets the parameter **angle** as degrees. Set this parameter to ``False`` to use angles in radians. Default is ``True``. For the point and axis parameters, if only one value is given, the value will be assumed to be an x-coordinate with the y- and z-coordinates equal to zero (0). If two values are given, they will be assumed to be x- and y-coordinates with the z-coordinate equal to zero (0). """ if len(point) <= 3 and len(axis) <= 3: p = Quaternion(0, *_makeListLen3(point)) axis_i, axis_j, axis_k = _makeListLen3(axis) if _hypot(axis_i, axis_j, axis_k) == 0: raise ValueError( 'The axis to rotate around must be a nonzero vector.') q = Quaternion.from_angle(angle*0.5, (axis_i, axis_j, axis_k), degrees=degrees) if abs(q) != 1.0: q = q.versor # Ensures q is a unit vector. p_prime = q * p * q.inverse() if rounding != -1: p_prime = round(p_prime, rounding) i_prime, j_prime, k_prime = p_prime.get_vector_components() return (i_prime, j_prime, k_prime) else: if len(point) > 3: problem = "'point'" elif len(axis) > 3: problem = "'axis'" else: problem = "'point' and 'axis'" raise IndexError( f"{problem} must be a tuple or list of three (3) values.")
def hyp(x, y): return _hypot(x, y)
def renderArea(self, width_, height_, srs, xmin_, ymin_, xmax_, ymax_, zoom): """ """ merc = Proj(srs) # use the center to figure out our UTM zone lon, lat = merc((xmin_ + xmax_)/2, (ymin_ + ymax_)/2, inverse=True) zone = lon2zone(lon) hemi = lat2hemi(lat) utm = Proj(proj='utm', zone=zone, datum='WGS84') # get to UTM coords (minlon, minlat), (maxlon, maxlat) = merc(xmin_, ymin_, inverse=1), merc(xmax_, ymax_, inverse=1) (xmin, ymin), (xmax, ymax) = utm(minlon, minlat), utm(maxlon, maxlat) # figure out how widely-spaced they should be pixels = _hypot(width_, height_) # number of pixels across the image units = _hypot(xmax - xmin, ymax - ymin) # number of UTM units across the image tick = self.tick * units/pixels # desired tick length in UTM units count = pixels / self.spacing # approximate number of lines across the image bound = units / count # too-precise step between lines in UTM units zeros = int(_ceil(_log(bound) / _log(10))) # this value gets used again to format numbers step = int(_pow(10, zeros)) # a step that falls right on the 10^n # and the outer UTM bounds xbot, xtop = int(xmin - xmin % step), int(xmax - xmax % step) + 2 * step ybot, ytop = int(ymin - ymin % step), int(ymax - xmax % step) + 2 * step # start doing things in pixels img = Image.new('RGBA', (width_, height_), (0xEE, 0xEE, 0xEE, 0x00)) draw = ImageDraw.ImageDraw(img) xform = transform(width_, height_, xmin_, ymax_, xmax_, ymin_) lines = [] labels = [] for col in range(xbot, xtop, step): # set up the verticals utms = [(col, y) for y in range(ybot, ytop, step/10)] mercs = [merc(*utm(x, y, inverse=1)) for (x, y) in utms] lines.append( [xform(x, y) for (x, y) in mercs] ) # and the tick marks for row in range(ybot, ytop, step/10): mercs = [merc(*utm(x, y, inverse=1)) for (x, y) in ((col, row), (col - tick, row))] lines.append( [xform(x, y) for (x, y) in mercs] ) for row in range(ybot, ytop, step): # set up the horizontals utms = [(x, row) for x in range(xbot, xtop, step/10)] mercs = [merc(*utm(x, y, inverse=1)) for (x, y) in utms] lines.append( [xform(x, y) for (x, y) in mercs] ) # and the tick marks for col in range(xbot, xtop, step/10): mercs = [merc(*utm(x, y, inverse=1)) for (x, y) in ((col, row), (col, row - tick))] lines.append( [xform(x, y) for (x, y) in mercs] ) # set up the intersection labels for x in range(xbot, xtop, step): for y in range(ybot, ytop, step): lon, lat = utm(x, y, inverse=1) grid = lonlat2grid(lon, lat) point = xform(*merc(lon, lat)) if self.display == 'utm': e = ('%07d' % x)[:-zeros] n = ('%07d' % y)[:-zeros] text = ' '.join( [grid, e, n] ) elif self.display == 'mgrs': e, n = Proj(proj='utm', zone=lon2zone(lon), datum='WGS84')(lon, lat) text = utm2mgrs(round(e), round(n), grid, zeros) labels.append( (point, text) ) # do the drawing bits for ((x, y), text) in labels: x, y = x + 2, y - 18 w, h = self.font.getsize(text) draw.rectangle((x - 2, y, x + w + 2, y + h), fill=(0xFF, 0xFF, 0xFF, 0x99)) for line in lines: draw.line(line, fill=(0xFF, 0xFF, 0xFF)) for line in lines: draw.line([(x-1, y-1) for (x, y) in line], fill=(0x00, 0x00, 0x00)) for ((x, y), text) in labels: x, y = x + 2, y - 18 draw.text((x, y), text, fill=(0x00, 0x00, 0x00), font=self.font) return img