Source code for pygimli.utils.positioning

"""Several tools for position-based."""
import numpy as np


[docs] def distToLine(x, y, lx, ly): """Compute minimum distance to segmented Line. Parameters ---------- x, y : iterable x and y positions lx, ly : iterable position of points creating a line """ assert len(x) == len(y), "Lengths of x/y not matching" assert len(lx) == len(ly), "Lengths of lx/ly not matching" dist2 = np.ones_like(x) * 1e9 for i in range(len(lx)-1): px = x - lx[i] py = y - ly[i] bx = lx[i + 1] - lx[i] by = ly[i + 1] - ly[i] t = (px * bx + by * py) / (bx**2 + by**2) t = np.maximum(np.minimum(t, 1), 0) dist2 = np.minimum(dist2, (px-t*bx)**2+(py-t*by)**2) return np.sqrt(dist2)
[docs] def pointInsidePolygon(x, y, polygon): """Determine whether a point is inside a closed polygon.""" n = len(polygon) inside = False p1x, p1y, *_ = polygon[0] for i in range(n + 1): p2x, p2y, *_ = polygon[i % n] if y > min(p1y, p2y) and y <= max(p1y, p2y) and x <= max(p1x, p2x): if p1y != p2y: xinters = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x if p1x == p2x or x <= xinters: inside = not inside p1x, p1y = p2x, p2y return inside
def detectLinesAlongAxis(rx, ry, axis='x'): """Split data in lines based on x/y axis.""" if axis == 'x': r = rx elif axis == 'y': r = ry else: print('Choose either *x* or *y* axis. Aborting this method ...') return dummy = np.zeros_like(rx, dtype=int) line = np.zeros_like(rx, dtype=int) li = 0 last_sign = np.sign(r[1] - r[0]) for ri in range(1, len(rx)): sign = np.sign(r[ri] - r[ri-1]) dummy[ri-1] = li if sign != last_sign: li += 1 last_sign *= -1 dummy[-1] = li return sortLines(rx, ry, line, dummy, axis) def detectLinesByDistance(rx, ry, minDist=200., axis='x'): """Split data in lines based on point distances.""" dummy = np.zeros_like(rx, dtype=int) line = np.zeros_like(rx, dtype=int) li = 0 for ri in range(1, len(rx)): dummy[ri-1] = li dist = np.sqrt((rx[ri]-rx[ri-1])**2 + (ry[ri]-ry[ri-1])**2) if dist > minDist: li += 1 dummy[-1] = li return sortLines(rx, ry, line, dummy, axis) def detectLinesBySpacing(rx, ry, vec, axis='x'): """Detect line changes by jumps in point spacing.""" if axis == 'x': r = rx elif axis == 'y': r = ry else: print('Choose either *x* or *y* axis. Aborting this method ...') return return np.argmin(np.abs(np.tile(r, (len(vec), 1)).T - vec), axis=1) def detectLinesByDirection(rx, ry): """Split data in lines for line-wise processing.""" dt = np.sqrt(np.diff(rx)**2 + np.diff(ry)**2) dtmin = np.median(dt) * 2 dx = np.round(np.diff(rx) / dt * 2) dy = np.round(np.diff(ry) / dt * 2) sdx = np.hstack((0, np.diff(np.sign(dx)), 0)) sdy = np.hstack((0, np.diff(np.sign(dy)), 0)) line = np.zeros_like(rx, dtype=int) nLine = 1 act = True for i, sdxi in enumerate(sdx): if sdxi != 0: act = not act if act: nLine += 1 if sdy[i] != 0: act = not act if act: nLine += 1 if i > 0 and dt[i-1] > dtmin: act = True nLine += 1 if act: line[i] = nLine return line def sortLines(rx, ry, line, dummy, axis): """Sort line elements by Rx or Ry coordinates.""" means = [] for li in np.unique(dummy): if axis == 'x': means.append(np.mean(ry[dummy==li], axis=0)) elif axis == 'y': means.append(np.mean(rx[dummy==li], axis=0)) lsorted = np.argsort(means) for li, lold in enumerate(lsorted): line[dummy == lold] = li + 1 return line
[docs] def detectLines(x, y, mode=None, axis='x', show=False): """Split data in lines for line-wise processing. Several modes are available: 'x'/'y': along coordinate axis spacing vector: by given spacing float: minimum distance """ if isinstance(mode, (str)): line = detectLinesAlongAxis(x, y, axis=mode) elif hasattr(mode, "__iter__"): line = detectLinesBySpacing(x, y, mode, axis=axis) elif isinstance(mode, (int, float)): line = detectLinesByDistance(x, y, mode, axis=axis) else: line = detectLinesByDirection(x, y) return line