Skip to content

Instantly share code, notes, and snippets.

@Dan-Patterson
Last active February 13, 2019 04:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Dan-Patterson/1764582f061b9176fd035925c98b9214 to your computer and use it in GitHub Desktop.
Save Dan-Patterson/1764582f061b9176fd035925c98b9214 to your computer and use it in GitHub Desktop.
Length/distance calculations using einsum and numpy
# -*- 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