Last active
February 13, 2019 04:40
-
-
Save Dan-Patterson/1764582f061b9176fd035925c98b9214 to your computer and use it in GitHub Desktop.
Length/distance calculations using einsum and numpy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
import numpy as np | |
def e_leng(a, close=False): | |
"""Length/distance between points in an array using einsum | |
Parameters | |
---------- | |
preprocessing : | |
use `_view_`, `_new_view_` or `_reshape_` with structured/recarrays | |
a : array-like | |
A list/array coordinate pairs, with ndim = 3 and the minimum | |
shape = (1,2,2), eg. (1,4,2) for a single line of 4 pairs | |
The minimum input needed is a pair, a sequence of pairs can be used. | |
Returns | |
------- | |
length : float | |
The total length/distance formed by the points | |
d_leng : float | |
The distances between points forming the array | |
(40.0, [array([[ 10., 10., 10., 10.]])]) | |
Notes | |
----- | |
>>> diff = g[:, :, 0:-1] - g[:, :, 1:] | |
>>> # for 4D | |
>>> d = np.einsum('ijk..., ijk...->ijk...', diff, diff).flatten() # or | |
>>> d = np.einsum('ijkl, ijkl->ijk', diff, diff).flatten() | |
>>> d = np.sum(np.sqrt(d) | |
""" | |
# | |
# d_leng = 0.0 | |
# ---- | |
def _cal(diff): | |
""" perform the calculation, see above | |
""" | |
d_leng = np.sqrt(np.einsum('ijk,ijk->ij', diff, diff)).squeeze() | |
length = np.sum(d_leng.flatten()) | |
return length, d_leng | |
def _close_ply(a): | |
"""close an open polyline""" | |
if not np.all(a[0] == a[-1]): | |
a = np.vstack((a, a[0])) | |
return a | |
# ---- | |
diffs = [] | |
a = np.atleast_2d(a) | |
if a.shape[0] == 1: | |
return 0.0 | |
if a.ndim == 2: | |
if close: | |
a = _close_ply(a) | |
a = np.reshape(a, (1,) + a.shape) | |
if a.ndim == 3: | |
if close: | |
a = np.array([_close_ply(i) for i in a]) | |
diff = a[:, 0:-1] - a[:, 1:] | |
length, d_leng = _cal(diff) | |
diffs.append(d_leng) | |
if a.ndim == 4: | |
length = 0.0 | |
if close: | |
tmp = [] | |
for i in a: | |
tmp.append(np.array([_close_ply(j) for j in i])) | |
a = np.array(tmp) | |
for i in range(a.shape[0]): | |
diff = a[i][:, 0:-1] - a[i][:, 1:] | |
leng, d_leng = _cal(diff) | |
diffs.append(d_leng) | |
length += leng | |
return length, diffs[0] | |
# =========================================================================== | |
# | |
if __name__ == "__main__": | |
"""Some values for testing | |
a = np.arange(10) | |
b = np.arange(10) | |
c1 = np.ones(10) | |
c_seq = np.arange(10) | |
c = np.array([1, 3, 5, 4, 2, 0, 1, 1, 1, 0]) | |
abc1 = np.array(list(zip(a, b, c1))) | |
abc_seq = np.array(list(zip(a, b, c_seq))) | |
abc = np.array(list(zip(a,b,c))) | |
# | |
# ---- test calculations | |
e_leng(abc1) # ---- total length, followed by segment length | |
e_leng(abc_seq) | |
e_leng(abc) # ---- total length, followed by segment length | |
theta = np.linspace(-4 * np.pi, 4 * np.pi, 100) | |
z = np.linspace(-2, 2, 100) | |
r = z**2 + 1 | |
x = r * np.sin(theta) | |
y = r * np.cos(theta) | |
xyz = np.array(list(zip(x,y,z))) | |
xyz_len = e_leng(xyz) | |
""" | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment