├── .gitignore ├── README.md ├── setup.py ├── traj_dist ├── __init__.py ├── __init__.pyc ├── cydist │ ├── __init__.py │ ├── __init__.pyc │ ├── basic_euclidean.c │ ├── basic_euclidean.pyx │ ├── basic_geographical.c │ ├── basic_geographical.pyx │ ├── discret_frechet.c │ ├── discret_frechet.pyx │ ├── dtw.c │ ├── dtw.pyx │ ├── edr.c │ ├── edr.pyx │ ├── erp.c │ ├── erp.pyx │ ├── frechet.c │ ├── frechet.pyx │ ├── hausdorff.c │ ├── hausdorff.pyx │ ├── lcss.c │ ├── lcss.pyx │ ├── segment_distance.c │ ├── segment_distance.pyx │ ├── sowd.c │ ├── sowd.pyx │ ├── sspd.c │ └── sspd.pyx ├── distance.py ├── example.py └── pydist │ ├── __init__.py │ ├── __init__.pyc │ ├── basic_euclidean.py │ ├── basic_euclidean.pyc │ ├── basic_geographical.py │ ├── basic_geographical.pyc │ ├── discret_frechet.py │ ├── discret_frechet.pyc │ ├── dtw.py │ ├── dtw.pyc │ ├── edr.py │ ├── edr.pyc │ ├── erp.py │ ├── erp.pyc │ ├── frechet.py │ ├── frechet.pyc │ ├── hausdorff.py │ ├── hausdorff.pyc │ ├── lcss.py │ ├── lcss.pyc │ ├── linecell.py │ ├── linecell.pyc │ ├── segment_distance.py │ ├── sowd.py │ ├── sowd.pyc │ ├── sspd.py │ └── sspd.pyc └── trajectory_distance.egg-info ├── PKG-INFO ├── SOURCES.txt ├── dependency_links.txt ├── pbr.json ├── requires.txt └── top_level.txt /.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | distance.pyc 3 | .idea/ 4 | build/ 5 | .DS_Store 6 | deprecated/ 7 | test/ 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # trajectory_distance 2 | ===================== 3 | 4 | **trajectory_distance** is a Python module for computing distance between trajectory objects. 5 | It is implemented in both Python and Cython. 6 | 7 | ## Description 8 | 9 | **trajectory_distance** contains 9 distances between trajectory. 10 | 11 | 1. SSPD (Symmetric Segment-Path Distance) 12 | 2. OWD (One-Way Distance) 13 | 3. Hausdorff 14 | 4. Frechet 15 | 5. Discret Frechet 16 | 6. DTW (Dynamic Time Warping) 17 | 7. LCSS (Longuest Common Subsequence) 18 | 8. ERP (Edit distance with Real Penalty) 19 | 9. EDR (Edit Distance on Real sequence) 20 | 21 | 22 | ## Dependencies 23 | 24 | trajectory_distance is tested to work under Python 2.7. 25 | 26 | The required dependencies to build the software are NumPy >= 1.9.1, Cython >= 0.21.2, shapely >= 1.5.6, Geohash and a working C/C++ compiler. 27 | 28 | ## Install 29 | 30 | This package uses distutils. To install in your home directory, use: 31 | 32 | ``` 33 | python setup.py install 34 | ``` 35 | 36 | ## How to use it 37 | 38 | You only need to import the distance module. 39 | 40 | ``` 41 | import traj_dist.distance as tdist 42 | ``` 43 | 44 | All distances are in this module. There is also two extra function 'cdist', and 'pdist' to compute distances between all trajectories in a list. 45 | 46 | Trajectory should be represented as 2-Dimensions numpy array. 47 | See traj_dist/example.py file. 48 | 49 | Some distance requires extra-parameters. 50 | See the help function for more information about how to use each distance. 51 | 52 | ## References 53 | 54 | 1. *P. Besse, B. Guillouet, J.-M. Loubes, and R. Francois, “Review and perspective for distance based trajectory clustering,” 55 | arXiv preprint arXiv:1508.04904, 2015.* 56 | 2. *B. Lin and J. Su, “Shapes based trajectory queries for moving objects,” 57 | in 58 | Proceedings of the 13th annual ACM international workshop on 59 | Geographic information systems 60 | . ACM, 2005, pp. 21–30.* 61 | 3. *F. Hausdorff, “Grundz uge der mengenlehre,” 1914* 62 | 4. *M. M. Fr 63 | echet, “Sur quelques points du calcul fonctionnel,” 64 | Rendiconti 65 | del Circolo Matematico di Palermo (1884-1940) 66 | , vol. 22, no. 1, pp. 67 | 1–72, 1906.* 68 | 5. *H. Alt and M. Godau, “Computing the frechet distance between two 69 | polygonal curves,” 70 | International Journal of Computational Geometry & 71 | Applications 72 | , vol. 5, no. 01n02, pp. 75–91, 1995.* 73 | 6. *D. J. Berndt and J. Clifford , “Using dynamic time warping to find patterns in time series.” in KDD workshop, vol. 10, no. 16. Seattle, WA, 1994, pp. 359–370* 74 | 7. *M. Vlachos, G. Kollios, and D. Gunopulos, “Discovering similar multi- 75 | dimensional trajectories,” in 76 | Data Engineering, 2002. Proceedings. 18th 77 | International Conference on 78 | .IEEE, 2002, pp. 673–684* 79 | 8. *L. Chen and R. Ng, “On the marriage of lp-norms and edit distance,” 80 | in 81 | Proceedings of the Thirtieth international conference on Very large 82 | data bases-Volume 30 83 | . VLDB Endowment, 2004, pp. 792–803.* 84 | 9. *L. Chen, M. T. 85 | ̈ 86 | Ozsu, and V. Oria, “Robust and fast similarity search for 87 | moving object trajectories,” in 88 | Proceedings of the 2005 ACM SIGMOD 89 | international conference on Management of data 90 | . ACM, 2005, pp. 91 | 491–502.* 92 | 10. *J.-G. Lee, J. Han, and K.-Y. Whang, “Trajectory clustering: a partition- 93 | and-group framework,” in 94 | Proceedings of the 2007 ACM SIGMOD 95 | international conference on Management of data 96 | . ACM, 2007, pp. 97 | 593–604.* 98 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | from distutils.extension import Extension 3 | from Cython.Distutils import build_ext 4 | import numpy 5 | 6 | ext_modules = [Extension("traj_dist.cydist.basic_geographical", [ "traj_dist/cydist/basic_geographical.pyx" ]), 7 | Extension("traj_dist.cydist.basic_euclidean", [ "traj_dist/cydist/basic_euclidean.pyx" ]), 8 | Extension("traj_dist.cydist.sspd", [ "traj_dist/cydist/sspd.pyx" ]), 9 | Extension("traj_dist.cydist.dtw", [ "traj_dist/cydist/dtw.pyx" ]), 10 | Extension("traj_dist.cydist.lcss", [ "traj_dist/cydist/lcss.pyx" ]), 11 | Extension("traj_dist.cydist.hausdorff", [ "traj_dist/cydist/hausdorff.pyx" ]), 12 | Extension("traj_dist.cydist.discret_frechet", [ "traj_dist/cydist/discret_frechet.pyx" ]), 13 | Extension("traj_dist.cydist.frechet", [ "traj_dist/cydist/frechet.pyx" ]), 14 | #Extension("traj_dist.cydist.distance", [ "traj_dist/cydist/distance.pyx" ]), 15 | Extension("traj_dist.cydist.segment_distance", [ "traj_dist/cydist/segment_distance.pyx" ]), 16 | Extension("traj_dist.cydist.sowd", [ "traj_dist/cydist/sowd.pyx" ]), 17 | Extension("traj_dist.cydist.erp", [ "traj_dist/cydist/erp.pyx" ]), 18 | Extension("traj_dist.cydist.edr", [ "traj_dist/cydist/edr.pyx" ])] 19 | 20 | setup( 21 | name = "trajectory_distance", 22 | version = "1.0", 23 | author = "Brendan Guillouet", 24 | author_email = "brendan.guillouet@gmail.com", 25 | cmdclass = { 'build_ext': build_ext }, 26 | ext_modules=ext_modules, 27 | include_dirs=[numpy.get_include()], 28 | install_requires = ["numpy>=1.9.1", "cython>=0.21.2", "shapely>=1.5.6", "Geohash"], 29 | description = "Distance to compare trajectories in Cython", 30 | packages = ["traj_dist", "traj_dist.cydist", "traj_dist.pydist"], 31 | ) 32 | -------------------------------------------------------------------------------- /traj_dist/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'bguillouet' 2 | -------------------------------------------------------------------------------- /traj_dist/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/__init__.pyc -------------------------------------------------------------------------------- /traj_dist/cydist/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'bguillouet' 2 | 3 | __all__=["sspd"] -------------------------------------------------------------------------------- /traj_dist/cydist/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/cydist/__init__.pyc -------------------------------------------------------------------------------- /traj_dist/cydist/basic_euclidean.pyx: -------------------------------------------------------------------------------- 1 | #cython: boundscheck=False 2 | #cython: wraparound=False 3 | 4 | STUFF = "Hi" 5 | 6 | from libc.math cimport sqrt 7 | from libc.math cimport fmin 8 | cimport numpy as np 9 | import numpy as np 10 | from cpython cimport bool 11 | 12 | 13 | 14 | cdef double _eucl_dist(double x1,double y1,double x2,double y2): 15 | """ 16 | Usage 17 | ----- 18 | L2-norm between point (x1,y1) and (x2,y2) 19 | 20 | Parameters 21 | ---------- 22 | param x1 : float 23 | param y1 : float 24 | param x2 : float 25 | param y2 : float 26 | 27 | Returns 28 | ------- 29 | dist : float 30 | L2-norm between (x1,y1) and (x2,y2) 31 | """ 32 | cdef double d,dx,dy 33 | dx=(x1-x2) 34 | dy=(y1-y2) 35 | dist=sqrt(dx*dx+dy*dy) 36 | return dist 37 | 38 | 39 | def c_eucl_dist(double x1,double y1,double x2,double y2): 40 | """ 41 | Usage 42 | ----- 43 | L2-norm between point (x1,y1) and (x2,y2) 44 | 45 | Parameters 46 | ---------- 47 | param x1 : float 48 | param y1 : float 49 | param x2 : float 50 | param y2 : float 51 | 52 | Returns 53 | ------- 54 | dist : float 55 | L2-norm between (x1,y1) and (x2,y2) 56 | """ 57 | cdef double d,dx,dy 58 | dx=(x1-x2) 59 | dy=(y1-y2) 60 | d=sqrt(dx*dx+dy*dy) 61 | return d 62 | 63 | 64 | 65 | cdef double _point_to_seg(double px, double py, double p1x, double p1y, double p2x, double p2y ): 66 | """ 67 | Usage 68 | ----- 69 | Point to segment distance between point (px, py) and segment delimited by (p1x, p1y) and (p2x, p2y) 70 | 71 | Parameters 72 | ---------- 73 | param px : float, abscissa of the point 74 | param py : float, ordinate of the point 75 | param p1x : float, abscissa of the first end point of the segment 76 | param p1y : float, ordinate of the first end point of the segment 77 | param p2x : float, abscissa of the second end point of the segment 78 | param p2y : float, ordinate of the second end point of the segment 79 | 80 | 81 | Returns 82 | ------- 83 | dpl: float 84 | Point to segment distance between p and s 85 | """ 86 | 87 | cdef double segl,u1,u,ix,iy,dpl 88 | if p1x==p2x and p1y==p2y: 89 | dpl=_eucl_dist(px,py,p1x,p1y) 90 | else: 91 | segl= _eucl_dist(p1x,p1y,p2x,p2y) 92 | u1 = (((px - p1x) * (p2x - p1x)) + ((py - p1y) * (p2y - p1y))) 93 | u = u1 / (segl * segl) 94 | 95 | if (u < 0.00001) or (u > 1): 96 | #// closest point does not fall within the line segment, take the shorter distance 97 | #// to an endpoint 98 | ix = _eucl_dist(px,py,p1x,p1y) 99 | iy = _eucl_dist(px,py,p2x,p2y) 100 | if ix > iy: 101 | dpl = iy 102 | else: 103 | dpl = ix 104 | else: 105 | # Intersecting point is on the line, use the formula 106 | ix = p1x + u * (p2x - p1x) 107 | iy = p1y + u * (p2y - p1y) 108 | dpl = _eucl_dist(px,py,ix,iy) 109 | 110 | return dpl 111 | 112 | def c_point_to_seg(double px, double py, double p1x, double p1y, double p2x, double p2y ): 113 | """ 114 | Usage 115 | ----- 116 | Point to segment distance between point (px, py) and segment delimited by (p1x, p1y) and (p2x, p2y) 117 | 118 | Parameters 119 | ---------- 120 | param px : float, abscissa of the point 121 | param py : float, ordinate of the point 122 | param p1x : float, abscissa of the first end point of the segment 123 | param p1y : float, ordinate of the first end point of the segment 124 | param p2x : float, abscissa of the second end point of the segment 125 | param p2y : float, ordinate of the second end point of the segment 126 | 127 | 128 | Returns 129 | ------- 130 | dpl: float 131 | Point to segment distance between p and s 132 | """ 133 | cdef double segl,u1,u,ix,iy,dpl 134 | if p1x==p2x and p1y==p2y: 135 | dpl=_eucl_dist(px,py,p1x,p1y) 136 | else: 137 | segl= _eucl_dist(p1x,p1y,p2x,p2y) 138 | u1 = (((px - p1x) * (p2x - p1x)) + ((py - p1y) * (p2y - p1y))) 139 | u = u1 / (segl * segl) 140 | 141 | if (u < 0.00001) or (u > 1): 142 | #// closest point does not fall within the line segment, take the shorter distance 143 | #// to an endpoint 144 | ix = _eucl_dist(px,py,p1x,p1y) 145 | iy = _eucl_dist(px,py,p2x,p2y) 146 | if ix > iy: 147 | dpl = iy 148 | else: 149 | dpl = ix 150 | else: 151 | # Intersecting point is on the line, use the formula 152 | ix = p1x + u * (p2x - p1x) 153 | iy = p1y + u * (p2y - p1y) 154 | dpl = _eucl_dist(px,py,ix,iy) 155 | 156 | return dpl 157 | 158 | cdef double _point_to_trajectory (double px,double py, np.ndarray[np.float64_t,ndim=2] t): 159 | """ 160 | Usage 161 | ----- 162 | Point-to-trajectory distance between point (px, py) and the trajectory t. 163 | The Point to trajectory distance is the minimum of point-to-segment distance between p and all segment s of t 164 | 165 | Parameters 166 | ---------- 167 | param px : float, abscissa of the point 168 | param py : float, ordinate of the point 169 | param t : len(t)x2 numpy_array 170 | 171 | Returns 172 | ------- 173 | dpt : float, 174 | Point-to-trajectory distance between p and trajectory t 175 | """ 176 | cdef double dpt,dist_j0 177 | cdef int nt,i 178 | cdef np.ndarray[np.float64_t,ndim=1] xt,yt 179 | 180 | nt=len(t) 181 | xt=t[:,0] 182 | yt=t[:,1] 183 | dist_j0=9e100 184 | for i from 0 <= i < (nt-1): 185 | dist_j0=fmin(dist_j0,_point_to_seg(px,py,xt[i],yt[i],xt[i+1],yt[i+1])) 186 | 187 | return dist_j0 188 | 189 | def c_point_to_trajectory (double px,double py, np.ndarray[np.float64_t,ndim=2] t): 190 | """ 191 | Usage 192 | ----- 193 | Point-to-trajectory distance between point (px, py) and the trajectory t. 194 | The Point to trajectory distance is the minimum of point-to-segment distance between p and all segment s of t 195 | 196 | Parameters 197 | ---------- 198 | param px : float, abscissa of the point 199 | param py : float, ordinate of the point 200 | param t : len(t)x2 numpy_array 201 | 202 | Returns 203 | ------- 204 | dpt : float, 205 | Point-to-trajectory distance between p and trajectory t 206 | """ 207 | cdef double dpt,dist_j0 208 | cdef int nt,i 209 | cdef np.ndarray[np.float64_t,ndim=1] xt,yt 210 | 211 | nt=len(t) 212 | xt=t[:,0] 213 | yt=t[:,1] 214 | dist_j0=9e100 215 | for i from 0 <= i < (nt-1): 216 | dist_j0=fmin(dist_j0,_point_to_seg(px,py,xt[i],yt[i],xt[i+1],yt[i+1])) 217 | 218 | return dist_j0 219 | 220 | cdef np.ndarray[np.float64_t,ndim=2] _circle_line_intersection(double px, double py, double s1x, double s1y, 221 | double 222 | s2x, double s2y, double eps): 223 | """ 224 | Usage 225 | ----- 226 | Find the intersections between the circle of radius eps and center (px, py) and the line delimited by points 227 | (s1x, s1y) and (s2x, s2y). 228 | It is supposed here that the intersection between them exists. If no, raise error 229 | 230 | Parameters 231 | ---------- 232 | param px : float, centre's abscissa of the circle 233 | param py : float, centre's ordinate of the circle 234 | eps : float, radius of the circle 235 | s1x : abscissa of the first point of the line 236 | s1y : ordinate of the first point of the line 237 | s2x : abscissa of the second point of the line 238 | s2y : ordinate of the second point of the line 239 | 240 | Returns 241 | ------- 242 | intersect : 2x2 numpy_array 243 | Coordinate of the two intersections. 244 | If the two intersections are the same, that's means that the line is a tangent of the circle. 245 | """ 246 | cdef double rac,y1,y2,m,c,A,B,C,delta,x,y,sdelta,x1,x2 247 | cdef np.ndarray[np.float64_t,ndim=2] intersect 248 | cdef bool delta_strict_inf_0,delta_inf_0,delta_strict_sup_0 249 | 250 | if s2x==s1x : 251 | rac=sqrt((eps*eps) - ((s1x-px)*(s1x-px))) 252 | y1 = py+rac 253 | y2 = py-rac 254 | intersect = np.array([[s1x,y1],[s1x,y2]]) 255 | else: 256 | m= (s2y-s1y)/(s2x-s1x) 257 | c= s2y-m*s2x 258 | A=m*m+1 259 | B=2*(m*c-m*py-px) 260 | C=py*py-eps*eps+px*px-2*c*py+c*c 261 | delta=B*B-4*A*C 262 | delta_inf_0 = delta <= 0 263 | delta_strict_sup_0 = delta > 0 264 | if delta_inf_0 : 265 | delta_strict_inf_0 = delta <0 266 | x = -B/(2*A) 267 | y = m*x+c 268 | intersect = np.array([[x,y],[x,y]]) 269 | elif delta_strict_sup_0 > 0 : 270 | sdelta = sqrt(delta) 271 | x1= (-B+sdelta)/(2*A) 272 | y1=m*x1+c 273 | x2= (-B-sdelta)/(2*A) 274 | y2=m*x2+c 275 | intersect = np.array([[x1,y1],[x2,y2]]) 276 | else : 277 | raise ValueError("The intersection between circle and line is supposed to exist") 278 | return intersect 279 | 280 | def c_circle_line_intersection(double px, double py, double s1x, double s1y, double 281 | s2x, double s2y, double eps): 282 | """ 283 | Usage 284 | ----- 285 | Find the intersections between the circle of radius eps and center (px, py) and the line delimited by points 286 | (s1x, s1y) and (s2x, s2y). 287 | It is supposed here that the intersection between them exists. If no, raise error 288 | 289 | Parameters 290 | ---------- 291 | param px : float, centre's abscissa of the circle 292 | param py : float, centre's ordinate of the circle 293 | param eps : float, radius of the circle 294 | param s1x : abscissa of the first point of the line 295 | param s1y : ordinate of the first point of the line 296 | param s2x : abscissa of the second point of the line 297 | param s2y : ordinate of the second point of the line 298 | 299 | Returns 300 | ------- 301 | intersect : 2x2 numpy_array 302 | Coordinate of the two intersections. 303 | If the two intersections are the same, that's means that the line is a tangent of the circle. 304 | """ 305 | cdef double rac,y1,y2,m,c,A,B,C,delta,x,y,sdelta,x1,x2 306 | cdef np.ndarray[np.float64_t,ndim=2] intersect 307 | cdef bool delta_strict_inf_0,delta_inf_0,delta_strict_sup_0 308 | 309 | if s2x==s1x : 310 | rac=sqrt((eps*eps) - ((s1x-px)*(s1x-px))) 311 | y1 = py+rac 312 | y2 = py-rac 313 | intersect = np.array([[s1x,y1],[s1x,y2]]) 314 | else: 315 | m= (s2y-s1y)/(s2x-s1x) 316 | c= s2y-m*s2x 317 | A=m*m+1 318 | B=2*(m*c-m*py-px) 319 | C=py*py-eps*eps+px*px-2*c*py+c*c 320 | delta=B*B-4*A*C 321 | delta_inf_0 = delta <= 0 322 | delta_strict_sup_0 = delta > 0 323 | if delta_inf_0 : 324 | delta_strict_inf_0 = delta <0 325 | x = -B/(2*A) 326 | y = m*x+c 327 | intersect = np.array([[x,y],[x,y]]) 328 | elif delta_strict_sup_0 > 0 : 329 | sdelta = sqrt(delta) 330 | x1= (-B+sdelta)/(2*A) 331 | y1=m*x1+c 332 | x2= (-B-sdelta)/(2*A) 333 | y2=m*x2+c 334 | intersect = np.array([[x1,y1],[x2,y2]]) 335 | else : 336 | raise ValueError("The intersection between circle and line is supposed to exist") 337 | return intersect -------------------------------------------------------------------------------- /traj_dist/cydist/basic_geographical.pyx: -------------------------------------------------------------------------------- 1 | STUFF = "Hi" 2 | 3 | from libc.math cimport sin 4 | from libc.math cimport cos 5 | from libc.math cimport acos 6 | from libc.math cimport asin 7 | from libc.math cimport atan2 8 | from libc.math cimport sqrt 9 | from libc.math cimport fmin 10 | from libc.math cimport fabs 11 | 12 | cimport numpy as np 13 | 14 | cdef float pi = 3.14159265 15 | cdef float rad = pi/180.0 16 | cdef int R = 6378137 17 | 18 | 19 | cdef double _great_circle_distance(double lon1,double lat1,double lon2,double lat2): 20 | """ 21 | Usage 22 | ----- 23 | Compute the great circle distance, in meter, between (lon1,lat1) and (lon2,lat2) 24 | 25 | Parameters 26 | ---------- 27 | param lat1: float, latitude of the first point 28 | param lon1: float, longitude of the first point 29 | param lat2: float, latitude of the second point 30 | param lon2: float, longitude of the second point 31 | 32 | Returns 33 | ------- 34 | d: float 35 | Great circle distance between (lon1,lat1) and (lon2,lat2) 36 | """ 37 | cdef double dLat,dLon,a,c,d 38 | 39 | dLat = (lat2 - lat1)*rad 40 | dLon = rad*(lon2 - lon1) 41 | a = (sin(dLat / 2) * sin(dLat / 2) + 42 | cos(rad*(lat1)) * cos(rad*(lat2)) * 43 | sin(dLon / 2) * sin(dLon / 2)) 44 | c = 2 * atan2(sqrt(a), sqrt(1 - a)) 45 | d = R * c 46 | return d 47 | 48 | 49 | def c_great_circle_distance(double lon1,double lat1,double lon2,double lat2): 50 | """ 51 | Usage 52 | ----- 53 | Compute the great circle distance, in meter, between (lon1,lat1) and (lon2,lat2) 54 | 55 | Parameters 56 | ---------- 57 | param lon1: float, longitude of the first point 58 | param lat1: float, latitude of the first point 59 | param lon2: float, longitude of the second point 60 | param lat2: float, latitude of the second point 61 | 62 | Returns 63 | ------- 64 | d: float 65 | Great circle distance between (lon1,lat1) and (lon2,lat2) 66 | """ 67 | cdef double dLat,dLon,a,c,d 68 | 69 | dLat = rad*(lat2 - lat1) 70 | dLon = rad*(lon2 - lon1) 71 | a = (sin(dLat / 2) * sin(dLat / 2) + 72 | cos(rad*(lat1)) * cos(rad*(lat2)) * 73 | sin(dLon / 2) * sin(dLon / 2)) 74 | c = 2 * atan2(sqrt(a), sqrt(1 - a)) 75 | d = R * c 76 | return d 77 | 78 | 79 | cdef double _initial_bearing(double lon1,double lat1,double lon2,double lat2): 80 | """ 81 | Usage 82 | ----- 83 | Bearing between (lon1,lat1) and (lon2,lat2), in degree. 84 | 85 | Parameters 86 | ---------- 87 | param lat1: float, latitude of the first point 88 | param lon1: float, longitude of the first point 89 | param lat2: float, latitude of the second point 90 | param lon2: float, longitude of the second point 91 | 92 | Returns 93 | ------- 94 | brng: float 95 | Bearing between (lon1,lat1) and (lon2,lat2), in degree. 96 | 97 | """ 98 | cdef double dLat,dLon,x,y,ibrng 99 | 100 | dLon = rad*(lon2 - lon1) 101 | y = sin(dLon) * cos(rad*(lat2)) 102 | x = cos(rad*(lat1))*sin(rad*(lat2)) - sin(rad*(lat1))*cos(rad*(lat2))*cos(dLon) 103 | ibrng = atan2(y, x) 104 | 105 | return ibrng 106 | 107 | def c_initial_bearing(double lon1,double lat1,double lon2,double lat2): 108 | """ 109 | Usage 110 | ----- 111 | Bearing between (lon1,lat1) and (lon2,lat2), in degree. 112 | 113 | Parameters 114 | ---------- 115 | param lat1: float, latitude of the first point 116 | param lon1: float, longitude of the first point 117 | param lat2: float, latitude of the second point 118 | param lon2: float, longitude of the second point 119 | 120 | Returns 121 | ------- 122 | brng: float 123 | Bearing between (lon1,lat1) and (lon2,lat2), in degree. 124 | 125 | """ 126 | cdef double dLat,dLon,x,y,ibrng 127 | 128 | dLon = rad*(lon2 - lon1) 129 | y = sin(dLon) * cos(rad*(lat2)) 130 | x = cos(rad*(lat1))*sin(rad*(lat2)) - sin(rad*(lat1))*cos(rad*(lat2))*cos(dLon) 131 | ibrng = atan2(y, x) 132 | 133 | return ibrng 134 | 135 | 136 | 137 | cdef double _cross_track_distance( double lon1, double lat1, double lon2, double lat2, double lon3, double lat3): 138 | """ 139 | Usage 140 | ----- 141 | Angular cross-track-distance of a point (lon3, lat3) from a great-circle path between (lon1, lat1) and (lon2, lat2) 142 | The sign of this distance tells which side of the path the third point is on. 143 | 144 | Parameters : 145 | 146 | param lat1: float, latitude of the first point 147 | param lon1: float, longitude of the first point 148 | param lat2: float, latitude of the second point 149 | param lon2: float, longitude of the second point 150 | param lat3: float, latitude of the third point 151 | param lon3: float, longitude of the third point 152 | 153 | Usage 154 | ----- 155 | crt: float 156 | the (angular) c_cross_track_distance 157 | 158 | """ 159 | cdef double d13,theta13,theta12,crt 160 | 161 | d13=_great_circle_distance(lon1,lat1,lon3,lat3) # distance from start point to third point 162 | theta13=_initial_bearing(lon1,lat1,lon3,lat3) # bearing from start point to third point 163 | theta12=_initial_bearing(lon1,lat1,lon2,lat2) # bearing from start point to end point 164 | 165 | crt= asin(sin(d13/R)*sin(theta13-theta12))*R 166 | 167 | return crt 168 | 169 | def c_cross_track_distance( double lon1, double lat1, double lon2, double lat2, double lon3, double lat3): 170 | """ 171 | Usage 172 | ----- 173 | Angular cross-track-distance of a point (lon3, lat3) from a great-circle path between (lon1, lat1) and (lon2, lat2) 174 | The sign of this distance tells which side of the path the third point is on. 175 | 176 | Parameters : 177 | 178 | param lat1: float, latitude of the first point 179 | param lon1: float, longitude of the first point 180 | param lat2: float, latitude of the second point 181 | param lon2: float, longitude of the second point 182 | param lat3: float, latitude of the third point 183 | param lon3: float, longitude of the third point 184 | 185 | Usage 186 | ----- 187 | crt: float 188 | the (angular) c_cross_track_distance 189 | 190 | """ 191 | cdef double d13,theta13,theta12,crt 192 | 193 | 194 | d13=_great_circle_distance(lon1,lat1,lon3,lat3) # distance from start point to third point 195 | theta13=_initial_bearing(lon1,lat1,lon3,lat3) # bearing from start point to third point 196 | theta12=_initial_bearing(lon1,lat1,lon2,lat2) # bearing from start point to end point 197 | 198 | crt= asin(sin(d13/R)*sin(theta13-theta12))*R 199 | 200 | return crt 201 | 202 | cdef double _along_track_distance(double crt,double lon1,double lat1,double lon3,double lat3): 203 | """ 204 | Usage 205 | ----- 206 | The along-track distance from the start point (lon1, lat1) to the closest point on the the path 207 | to the third point (lon3, lat3). 208 | 209 | Parameters 210 | ---------- 211 | param lat1: float, latitude of the first point 212 | param lon1: float, longitude of the first point 213 | param lat3: float, latitude of the third point 214 | param lon3: float, longitude of the third point 215 | param crt : float, c_cross_track_distance 216 | 217 | Returns 218 | ------- 219 | alt: float 220 | The along-track distance 221 | """ 222 | 223 | cdef double d13,alt 224 | 225 | d13=_great_circle_distance(lon1,lat1,lon3,lat3) 226 | 227 | alt=acos(cos(d13/R)/cos(crt/R)) * R 228 | return alt 229 | 230 | def c_along_track_distance(double crt,double lon1,double lat1,double lon3,double lat3): 231 | """ 232 | Usage 233 | ----- 234 | The along-track distance from the start point (lon1, lat1) to the closest point on the the path 235 | to the third point (lon3, lat3). 236 | 237 | Parameters 238 | ---------- 239 | param lat1: float, latitude of the first point 240 | param lon1: float, longitude of the first point 241 | param lat3: float, latitude of the third point 242 | param lon3: float, longitude of the third point 243 | param crt : float, c_cross_track_distance 244 | 245 | Returns 246 | ------- 247 | alt: float 248 | The along-track distance 249 | """ 250 | 251 | cdef double d13,alt 252 | 253 | d13=_great_circle_distance(lon1,lat1,lon3,lat3) 254 | 255 | alt=acos(cos(d13/R)/cos(crt/R)) * R 256 | return alt 257 | 258 | 259 | cdef double _point_to_path(double lon1,double lat1,double lon2,double lat2,double lon3,double lat3): 260 | """ 261 | Usage 262 | ----- 263 | The point-to-path distance between point (lon3, lat3) and path delimited by (lon1, lat1) and (lon2, lat2). 264 | The point-to-path distance is the cross_track distance between the great circle path if the projection of 265 | the third point lies on the path. If it is not on the path, return the minimum of the 266 | c_great_circle_distance between the first and the third or the second and the third point. 267 | 268 | Parameters 269 | ---------- 270 | param lat1: float, latitude of the first point 271 | param lon1: float, longitude of the first point 272 | param lat2: float, latitude of the second point 273 | param lon2: float, longitude of the second point 274 | param lat3: float, latitude of the third point 275 | param lon3: float, longitude of the third point 276 | 277 | Returns 278 | ------- 279 | 280 | ptp : float 281 | The point-to-path distance between point (lon3, lat3) and path delimited by (lon1, lat1) and (lon2, lat2) 282 | 283 | """ 284 | cdef double crt,d1p,d2p,d12 285 | crt=_cross_track_distance(lon1,lat1,lon2,lat2,lon3,lat3) 286 | d1p=_along_track_distance(crt,lon1,lat1,lon3,lat3) 287 | d2p=_along_track_distance(crt,lon2,lat2,lon3,lat3) 288 | d12=_great_circle_distance(lon1,lat1,lon2,lat2) 289 | if (d1p > d12) or (d2p > d12): 290 | crt=fmin(_great_circle_distance(lon1,lat1,lon3,lat3),_great_circle_distance(lon2,lat2,lon3,lat3)) 291 | else: 292 | crt=fabs(crt) 293 | return crt 294 | 295 | def c_point_to_path(double lon1,double lat1,double lon2,double lat2,double lon3,double lat3): 296 | """ 297 | Usage 298 | ----- 299 | The point-to-path distance between point (lon3, lat3) and path delimited by (lon1, lat1) and (lon2, lat2). 300 | The point-to-path distance is the cross_track distance between the great circle path if the projection of 301 | the third point lies on the path. If it is not on the path, return the minimum of the 302 | c_great_circle_distance between the first and the third or the second and the third point. 303 | 304 | Parameters 305 | ---------- 306 | param lat1: float, latitude of the first point 307 | param lon1: float, longitude of the first point 308 | param lat2: float, latitude of the second point 309 | param lon2: float, longitude of the second point 310 | param lat3: float, latitude of the third point 311 | param lon3: float, longitude of the third point 312 | 313 | Returns 314 | ------- 315 | 316 | ptp : float 317 | The point-to-path distance between point (lon3, lat3) and path delimited by (lon1, lat1) and (lon2, lat2) 318 | 319 | """ 320 | cdef double crt,d1p,d2p,d12 321 | crt=_cross_track_distance(lon1,lat1,lon2,lat2,lon3,lat3) 322 | d1p=_along_track_distance(crt,lon1,lat1,lon3,lat3) 323 | d2p=_along_track_distance(crt,lon2,lat2,lon3,lat3) 324 | d12=_great_circle_distance(lon1,lat1,lon2,lat2) 325 | if (d1p > d12) or (d2p > d12): 326 | crt=fmin(_great_circle_distance(lon1,lat1,lon3,lat3),_great_circle_distance(lon2,lat2,lon3,lat3)) 327 | else: 328 | crt=fabs(crt) 329 | return crt 330 | -------------------------------------------------------------------------------- /traj_dist/cydist/discret_frechet.pyx: -------------------------------------------------------------------------------- 1 | STUFF = "Hi" 2 | 3 | from libc.math cimport fmin 4 | from libc.math cimport fmax 5 | 6 | cimport numpy as np 7 | import numpy as np 8 | 9 | from basic_euclidean import c_eucl_dist 10 | 11 | cdef double _c( np.ndarray[np.float64_t,ndim=2] ca,int i, int j, np.ndarray[np.float64_t,ndim=2] P,np.ndarray[np 12 | .float64_t,ndim=2] Q): 13 | 14 | if ca[i,j] > -1: 15 | return ca[i,j] 16 | elif i == 0 and j == 0: 17 | ca[i,j] = c_eucl_dist(P[0,0],P[0,1],Q[0,0],Q[0,1]) 18 | elif i > 0 and j == 0: 19 | ca[i,j] = fmax(_c(ca,i-1,0,P,Q),c_eucl_dist(P[i,0],P[i,1],Q[0,0],Q[0,1])) 20 | elif i == 0 and j > 0: 21 | ca[i,j] = fmax(_c(ca,0,j-1,P,Q),c_eucl_dist(P[0,0],P[0,1],Q[j,0],Q[j,1])) 22 | elif i > 0 and j > 0: 23 | ca[i,j] = fmax(fmin(_c(ca,i-1,j,P,Q),fmin(_c(ca,i-1,j-1,P,Q),_c(ca,i,j-1,P,Q))),c_eucl_dist(P[i,0],P[i,1], 24 | Q[j,0], Q[j,1])) 25 | else: 26 | ca[i,j] = float("inf") 27 | return ca[i,j] 28 | 29 | def c_discret_frechet(P,Q): 30 | """ 31 | Usage 32 | ----- 33 | Compute the discret frechet distance between trajectories P and Q 34 | 35 | Parameters 36 | ---------- 37 | param P : px2 array_like, Trajectory P 38 | param Q : qx2 array_like, Trajectory Q 39 | 40 | Returns 41 | ------- 42 | frech : float, the discret frechet distance between trajectories P and Q 43 | """ 44 | ca = np.ones((len(P),len(Q))) 45 | ca = np.multiply(ca,-1) 46 | return _c(ca,len(P)-1,len(Q)-1,P,Q) 47 | 48 | -------------------------------------------------------------------------------- /traj_dist/cydist/dtw.pyx: -------------------------------------------------------------------------------- 1 | STUFF = "Hi" 2 | 3 | from libc.math cimport fmin 4 | 5 | cimport numpy as np 6 | import numpy as np 7 | from numpy.math cimport INFINITY 8 | 9 | from basic_euclidean import c_eucl_dist 10 | from basic_geographical import c_great_circle_distance 11 | 12 | ############### 13 | #### DTW ###### 14 | ############### 15 | 16 | def c_e_dtw(np.ndarray[np.float64_t,ndim=2] t0, np.ndarray[np.float64_t,ndim=2] t1): 17 | """ 18 | Usage 19 | ----- 20 | The Dynamic-Time Warping distance between trajectory t0 and t1. 21 | 22 | Parameters 23 | ---------- 24 | param t0 : len(t0)x2 numpy_array 25 | param t1 : len(t1)x2 numpy_array 26 | 27 | Returns 28 | ------- 29 | dtw : float 30 | The Dynamic-Time Warping distance between trajectory t0 and t1 31 | """ 32 | cdef int n0,n1,i,j 33 | cdef np.ndarray[np.float64_t,ndim=2] C 34 | cdef double x0,y0,x1,y1,dtw 35 | 36 | n0 = len(t0)+1 37 | n1 = len(t1)+1 38 | C=np.zeros((n0,n1)) 39 | 40 | C[1:,0]=INFINITY 41 | C[0,1:]=INFINITY 42 | for i from 1 <= i < n0: 43 | for j from 1 <= j < n1: 44 | x0=t0[i-1,0] 45 | y0=t0[i-1,1] 46 | x1=t1[j-1,0] 47 | y1=t1[j-1,1] 48 | C[i,j]=c_eucl_dist(x0,y0,x1,y1) + fmin(fmin(C[i,j-1],C[i-1,j-1]),C[i-1,j]) 49 | dtw = C[n0-1,n1-1] 50 | return dtw 51 | 52 | 53 | def c_g_dtw(np.ndarray[np.float64_t,ndim=2] t0, np.ndarray[np.float64_t,ndim=2] t1): 54 | """ 55 | Usage 56 | ----- 57 | The Dynamic-Time Warping distance between trajectory t0 and t1. 58 | 59 | Parameters 60 | ---------- 61 | param t0 : len(t0)x2 numpy_array 62 | param t1 : len(t1)x2 numpy_array 63 | 64 | Returns 65 | ------- 66 | dtw : float 67 | The Dynamic-Time Warping distance between trajectory t0 and t1 68 | """ 69 | cdef int n0,n1,i,j 70 | cdef np.ndarray[np.float64_t,ndim=2] C 71 | cdef double x0,y0,x1,y1,dtw 72 | 73 | n0 = len(t0)+1 74 | n1 = len(t1)+1 75 | C=np.zeros((n0,n1)) 76 | 77 | C[1:,0]=INFINITY 78 | C[0,1:]=INFINITY 79 | for i from 1 <= i < n0: 80 | for j from 1 <= j < n1: 81 | x0=t0[i-1,0] 82 | y0=t0[i-1,1] 83 | x1=t1[j-1,0] 84 | y1=t1[j-1,1] 85 | C[i,j]=c_great_circle_distance(x0,y0,x1,y1) + fmin(fmin(C[i,j-1],C[i-1,j-1]),C[i-1,j]) 86 | dtw = C[n0-1,n1-1] 87 | return dtw 88 | -------------------------------------------------------------------------------- /traj_dist/cydist/edr.pyx: -------------------------------------------------------------------------------- 1 | STUFF = "Hi" 2 | 3 | from libc.math cimport fmax 4 | from libc.math cimport fmin 5 | 6 | 7 | cimport numpy as np 8 | import numpy as np 9 | 10 | 11 | from basic_euclidean import c_eucl_dist 12 | from basic_geographical import c_great_circle_distance 13 | 14 | def c_e_edr(np.ndarray[np.float64_t,ndim=2] t0, np.ndarray[np.float64_t,ndim=2] t1, float eps): 15 | """ 16 | Usage 17 | ----- 18 | The Edit Distance on Real sequence distance between trajectory t0 and t1. 19 | 20 | Parameters 21 | ---------- 22 | param t0 : len(t0)x2 numpy_array 23 | param t1 : len(t1)x2 numpy_array 24 | eps : float 25 | 26 | Returns 27 | ------- 28 | edr : float 29 | The Edit Distance on Real sequence distance between trajectory t0 and t1 30 | """ 31 | cdef int n0,n1,i,j,subcost 32 | cdef np.ndarray[np.float64_t,ndim=2] C 33 | cdef double x0,y0,x1,y1,lcss 34 | 35 | n0 = len(t0)+1 36 | n1 = len(t1)+1 37 | 38 | # An (m+1) times (n+1) matrix 39 | C=np.zeros((n0,n1)) 40 | 41 | for i from 1 <= i < n0: 42 | for j from 1 <= j < n1: 43 | x0=t0[i-1,0] 44 | y0=t0[i-1,1] 45 | x1=t1[j-1,0] 46 | y1=t1[j-1,1] 47 | if c_eucl_dist(x0,y0,x1,y1)eps 46 | if s1x == s2x and s1y==s2y: 47 | if c_eucl_dist(px,py,s1x,s1y) > eps: 48 | lf = np.array([-1.0, -1.0]) 49 | else: 50 | lf = np.array([0.0,1.0]) 51 | else: 52 | if pts_sup_eps: 53 | #print("No Intersection") 54 | lf=np.array([-1.0,-1.0]) 55 | else : 56 | segl=c_eucl_dist(s1x,s1y,s2x,s2y) 57 | segl2=segl*segl 58 | intersect = c_circle_line_intersection(px,py,s1x,s1y,s2x,s2y,eps) 59 | i1x = intersect[0,0] 60 | i2x = intersect[1,0] 61 | i1y = intersect[0,1] 62 | i2y = intersect[1,1] 63 | i1x_dif_i2x = i1x!=i2x 64 | i1y_dif_i2y = i1y!=i2y 65 | if i1x_dif_i2x or i1y_dif_i2y: 66 | u1 = (((i1x - s1x) * (s2x - s1x)) + ((i1y - s1y) * (s2y - s1y)))/segl2 67 | u2 = (((i2x - s1x) * (s2x - s1x)) + ((i2y - s1y) * (s2y - s1y)))/segl2 68 | ordered_point=np.array(sorted((0,1,u1,u2))) 69 | lf= ordered_point[1:3] 70 | else : 71 | if px == s1x and py==s1y: 72 | lf = np.array([0.0, 0.0]) 73 | elif px == s2x and py==s2y: 74 | lf = np.array([1.0, 1.0]) 75 | else: 76 | u1 = (((i1x - s1x) * (s2x - s1x)) + ((i1y - s1y) * (s2y - s1y)))/segl2 77 | u1_sup_0 = u1 >=0 78 | u2_inf_1 = u1 <=1 79 | if u1_sup_0 and u2_inf_1: 80 | lf=np.array([u1,u1]) 81 | else: 82 | lf=np.array([-1.0,-1.0]) 83 | return lf 84 | 85 | 86 | def c_free_line(double px, double py, double eps, double s1x, double s1y, double s2x, double s2y): 87 | """ 88 | Usage 89 | ----- 90 | Return the free space in the segment s, from point p. 91 | This free space is the set of all point in s whose distance from p is at most eps. 92 | Since s is a segment, the free space is also a segment. 93 | We return a 1x2 array whit the fraction of the segment s which are in the free space. 94 | If no part of s are in the free space, return [-1,-1] 95 | 96 | Parameters 97 | ---------- 98 | param px : float, centre's abscissa of the circle 99 | param py : float, centre's ordinate of the circle 100 | param eps : float, radius of the circle 101 | param s1x : abscissa of the first end point of the segment 102 | param s1y : ordinate of the first end point of the segment 103 | param s2x : abscissa of the second end point of the segment 104 | param s2y : ordinate of the second end point of the segment 105 | 106 | Returns 107 | ------- 108 | lf : 1x2 numpy_array 109 | fraction of segment which is in the free space (i.e [0.3,0.7], [0.45,1], ...) 110 | If no part of s are in the free space, return [-1,-1] 111 | """ 112 | cdef np.ndarray[np.float64_t,ndim=2] intersect 113 | cdef np.ndarray[np.float64_t,ndim=1] lf,ordered_point 114 | cdef double i1x,i1y,u1,i2x,i2y,u2,segl,segl2 115 | cdef bool pts_sup_eps,i1x_dif_i2x,i1y_dif_i2y,u1_sup_0,u2_inf_1 116 | 117 | pts_sup_eps = c_point_to_seg(px,py,s1x,s1y,s2x,s2y)>eps 118 | 119 | if s1x == s2x and s1y==s2y: 120 | if c_eucl_dist(px,py,s1x,s1y) > eps: 121 | lf = np.array([-1.0, -1.0]) 122 | else: 123 | lf = np.array([0.0,1.0]) 124 | else: 125 | if pts_sup_eps: 126 | #print("No Intersection") 127 | lf=np.array([-1.0,-1.0]) 128 | else : 129 | segl=c_eucl_dist(s1x,s1y,s2x,s2y) 130 | segl2=segl*segl 131 | intersect = c_circle_line_intersection(px,py,s1x,s1y,s2x,s2y,eps) 132 | i1x = intersect[0,0] 133 | i2x = intersect[1,0] 134 | i1y = intersect[0,1] 135 | i2y = intersect[1,1] 136 | i1x_dif_i2x = i1x!=i2x 137 | i1y_dif_i2y = i1y!=i2y 138 | if i1x_dif_i2x or i1y_dif_i2y: 139 | u1 = (((i1x - s1x) * (s2x - s1x)) + ((i1y - s1y) * (s2y - s1y)))/segl2 140 | u2 = (((i2x - s1x) * (s2x - s1x)) + ((i2y - s1y) * (s2y - s1y)))/segl2 141 | ordered_point=np.array(sorted((0,1,u1,u2))) 142 | lf= ordered_point[1:3] 143 | else : 144 | if px == s1x and py==s1y: 145 | lf = np.array([0.0, 0.0]) 146 | elif px == s2x and py==s2y: 147 | lf = np.array([1.0, 1.0]) 148 | else: 149 | u1 = (((i1x - s1x) * (s2x - s1x)) + ((i1y - s1y) * (s2y - s1y)))/segl2 150 | u1_sup_0 = u1 >=0 151 | u2_inf_1 = u1 <=1 152 | if u1_sup_0 and u2_inf_1: 153 | lf=np.array([u1,u1]) 154 | else: 155 | lf=np.array([-1.0,-1.0]) 156 | return lf 157 | 158 | cdef _compute_LF_BF(np.ndarray[np.float64_t,ndim=2] P, np.ndarray[np.float64_t,ndim=2] Q, int p, int q, 159 | double eps): 160 | """ 161 | Usage 162 | ----- 163 | Compute all the free space on the boundary of cells in the diagram for polygonal chains P and Q and the given eps 164 | LF[(i,j)] is the free space of segments [Pi,Pi+1] from point Qj 165 | BF[(i,j)] is the free space of segment [Qj,Qj+1] from point Pj 166 | 167 | Parameters 168 | ---------- 169 | param P : px2 numpy_array, Trajectory P 170 | param Q : qx2 numpy_array, Trajectory Q 171 | param p : float, number of points in Trajectory P 172 | param q : float, number of points in Trajectory Q 173 | param eps : float, reachability distance 174 | 175 | Returns 176 | ------- 177 | LF : dict, free spaces of segments of P from points of Q 178 | BF : dict, free spaces of segments of Q from points of P 179 | """ 180 | 181 | cdef dict LF,BF 182 | cdef int j,i 183 | cdef double Q_j0,Q_j1,Q_j10,Q_j11,P_i0,P_i1,P_i10,P_i11 184 | 185 | LF={} 186 | for j from 0 <= j < q: 187 | for i from 0 <= i < p-1 : 188 | Q_j0=Q[j,0] 189 | Q_j1=Q[j,1] 190 | P_i0=P[i,0] 191 | P_i1=P[i,1] 192 | P_i10=P[i+1,0] 193 | P_i11=P[i+1,1] 194 | 195 | LF.update({(i,j):_free_line(Q_j0,Q_j1,eps,P_i0,P_i1,P_i10,P_i11)}) 196 | BF={} 197 | for j from 0 <= j < q-1: 198 | for i from 0 <= i < p : 199 | Q_j0=Q[j,0] 200 | Q_j1=Q[j,1] 201 | Q_j10=Q[j+1,0] 202 | Q_j11=Q[j+1,1] 203 | P_i0=P[i,0] 204 | P_i1=P[i,1] 205 | 206 | BF.update({(i,j):_free_line(P_i0,P_i1,eps,Q_j0,Q_j1,Q_j10,Q_j11)}) 207 | return LF,BF 208 | 209 | def c_compute_LF_BF(np.ndarray[np.float64_t,ndim=2] P, np.ndarray[np.float64_t,ndim=2] Q, int p, int q, 210 | double eps): 211 | """ 212 | Usage 213 | ----- 214 | Compute all the free space on the boundary of cells in the diagram for polygonal chains P and Q and the given eps 215 | LF[(i,j)] is the free space of segments [Pi,Pi+1] from point Qj 216 | BF[(i,j)] is the free space of segment [Qj,Qj+1] from point Pj 217 | 218 | Parameters 219 | ---------- 220 | param P : px2 numpy_array, Trajectory P 221 | param Q : qx2 numpy_array, Trajectory Q 222 | param p : float, number of points in Trajectory P 223 | param q : float, number of points in Trajectory Q 224 | param eps : float, reachability distance 225 | 226 | Returns 227 | ------- 228 | LF : dict, free spaces of segments of P from points of Q 229 | BF : dict, free spaces of segments of Q from points of P 230 | """ 231 | 232 | cdef dict LF,BF 233 | cdef int j,i 234 | cdef double Q_j0,Q_j1,Q_j10,Q_j11,P_i0,P_i1,P_i10,P_i11 235 | 236 | LF={} 237 | for j from 0 <= j < q: 238 | for i from 0 <= i < p-1 : 239 | Q_j0=Q[j,0] 240 | Q_j1=Q[j,1] 241 | P_i0=P[i,0] 242 | P_i1=P[i,1] 243 | P_i10=P[i+1,0] 244 | P_i11=P[i+1,1] 245 | 246 | LF.update({(i,j):_free_line(Q_j0,Q_j1,eps,P_i0,P_i1,P_i10,P_i11)}) 247 | BF={} 248 | for j from 0 <= j < q-1: 249 | for i from 0 <= i < p: 250 | Q_j0=Q[j,0] 251 | Q_j1=Q[j,1] 252 | Q_j10=Q[j+1,0] 253 | Q_j11=Q[j+1,1] 254 | P_i0=P[i,0] 255 | P_i1=P[i,1] 256 | 257 | BF.update({(i,j):_free_line(P_i0,P_i1,eps,Q_j0,Q_j1,Q_j10,Q_j11)}) 258 | return LF,BF 259 | 260 | cdef _compute_LR_BR(dict LF, dict BF,int p, int q): 261 | """ 262 | Usage 263 | ----- 264 | Compute all the free space,that are reachable from the origin (P[0,0],Q[0,0]) on the boundary of cells 265 | in the diagram for polygonal chains P and Q and the given free spaces LR and BR 266 | 267 | LR[(i,j)] is the free space, reachable from the origin, of segment [Pi,Pi+1] from point Qj 268 | BR[(i,j)] is the free space, reachable from the origin, of segment [Qj,Qj+1] from point Pj 269 | 270 | Parameters 271 | ---------- 272 | LF : dict, free spaces of segments of P from points of Q 273 | BF : dict, free spaces of segments of Q from points of P 274 | param p : float, number of points in Trajectory P 275 | param q : float, number of points in Trajectory Q 276 | 277 | Returns 278 | ------- 279 | rep : bool, return true if frechet distance is inf to eps 280 | LR : dict, is the free space, reachable from the origin, of segments of P from points of Q 281 | BR : dict, is the free space, reachable from the origin, of segments of Q from points of P 282 | """ 283 | 284 | cdef int i,j 285 | cdef dict LR,BR 286 | cdef bool rep 287 | 288 | if not(LF[(0,0)][0] <=0 and BF[(0,0)][0] <=0 and LF[(p-2,q-1)][1] >=1 and BF[(p-1,q-2)][1] >=1 ) : 289 | rep = False 290 | LR = {} 291 | BR = {} 292 | else: 293 | LR = {(0,0):True} 294 | BR = {(0,0):True} 295 | for i from 1 <= i < p-1: 296 | 297 | if (LF[(i,0)][0]!=-1.0 or LF[(i,0)][1]!=-1) and (LF[(i-1,0)][0]==0 and LF[(i-1,0)][1]==1): 298 | LR[(i,0)]=True 299 | else: 300 | LR[(i,0)]=False 301 | for j from 1 <= j < q-1: 302 | if (BF[(0,j)][0]!=-1.0 or BF[(0,j)][1]!=-1.0) and (BF[(0,j-1)][0]==0 and BF[(0,j-1)][1]==1): 303 | BR[(0,j)]=True 304 | else: 305 | BR[(0,j)]=False 306 | for i from 0 <= i < p-1: 307 | for j from 0 <= j < q-1: 308 | if LR[(i,j)] or BR[(i,j)]: 309 | if LF[(i,j+1)][0]!= -1.0 or LF[(i,j+1)][1]!=-1.0: 310 | LR[(i,j+1)]=True 311 | else: 312 | LR[(i,j+1)]=False 313 | if BF[(i+1,j)][0]!=-1.0 or BF[(i+1,j)][1]!=-1.0: 314 | BR[(i+1,j)]=True 315 | else: 316 | BR[(i+1,j)]=False 317 | else: 318 | LR[(i,j+1)]=False 319 | BR[(i+1,j)]=False 320 | rep = BR[(p-2,q-2)] or LR[(p-2,q-2)] 321 | return rep,LR,BR 322 | 323 | def c_compute_LR_BR(dict LF, dict BF,int p, int q): 324 | """ 325 | Usage 326 | ----- 327 | Compute all the free space,that are reachable from the origin (P[0,0],Q[0,0]) on the boundary of cells 328 | in the diagram for polygonal chains P and Q and the given free spaces LR and BR 329 | 330 | LR[(i,j)] is the free space, reachable from the origin, of segment [Pi,Pi+1] from point Qj 331 | BR[(i,j)] is the free space, reachable from the origin, of segment [Qj,Qj+1] from point Pj 332 | 333 | Parameters 334 | ---------- 335 | LF : dict, free spaces of segments of P from points of Q 336 | BF : dict, free spaces of segments of Q from points of P 337 | param p : float, number of points in Trajectory P 338 | param q : float, number of points in Trajectory Q 339 | 340 | Returns 341 | ------- 342 | rep : bool, return true if frechet distance is inf to eps 343 | LR : dict, is the free space, reachable from the origin, of segments of P from points of Q 344 | BR : dict, is the free space, reachable from the origin, of segments of Q from points of P 345 | """ 346 | 347 | cdef int i,j 348 | cdef dict LR,BR 349 | cdef bool rep 350 | 351 | if not(LF[(0,0)][0] <=0 and BF[(0,0)][0] <=0 and LF[(p-2,q-1)][1] >=1 and BF[(p-1,q-2)][1] >=1 ) : 352 | rep = False 353 | LR={} 354 | BR={} 355 | else: 356 | LR = {(0,0):True} 357 | BR = {(0,0):True} 358 | for i from 0 <= i < p-1: 359 | 360 | if (LF[(i,0)][0]!=-1.0 or LF[(i,0)][1]!=-1) and (LF[(i-1,0)][0]==0 and LF[(i-1,0)][1]==1): 361 | LR[(i,0)]=True 362 | else: 363 | LR[(i,0)]=False 364 | for j from 1 <= j < q-1: 365 | if (BF[(0,j)][0]!=-1.0 or BF[(0,j)][1]!=-1.0) and (BF[(0,j-1)][0]==0 and BF[(0,j-1)][1]==1): 366 | BR[(0,j)]=True 367 | else: 368 | BR[(0,j)]=False 369 | for i from 0 <= i < p-1: 370 | for j from 0 <= j < q-1: 371 | if LR[(i,j)] or BR[(i,j)]: 372 | if LF[(i,j+1)][0]!= -1.0 or LF[(i,j+1)][1]!=-1.0: 373 | LR[(i,j+1)]=True 374 | else: 375 | LR[(i,j+1)]=False 376 | if BF[(i+1,j)][0]!=-1.0 or BF[(i+1,j)][1]!=-1.0: 377 | BR[(i+1,j)]=True 378 | else: 379 | BR[(i+1,j)]=False 380 | else: 381 | LR[(i,j+1)]=False 382 | BR[(i+1,j)]=False 383 | rep = BR[(p-2,q-2)] or LR[(p-2,q-2)] 384 | return rep,LR,BR 385 | 386 | 387 | cdef bool _decision_problem(np.ndarray[np.float64_t,ndim=2] P, np.ndarray[np.float64_t,ndim=2] Q,int p,int q, double 388 | eps): 389 | """ 390 | Usage 391 | ----- 392 | Test is the frechet distance between trajectories P and Q are inferior to eps 393 | 394 | Parameters 395 | ---------- 396 | param P : px2 numpy_array, Trajectory P 397 | param Q : qx2 numpy_array, Trajectory Q 398 | param p : float, number of points in Trajectory P 399 | param q : float, number of points in Trajectory Q 400 | param eps : float, reachability distance 401 | 402 | Returns 403 | ------- 404 | rep : bool, return true if frechet distance is inf to eps 405 | """ 406 | cdef dict LF,BF 407 | cdef bool rep 408 | 409 | LF,BF= _compute_LF_BF(P,Q,p,q,eps) 410 | rep,_,_ =_compute_LR_BR(LF,BF,p,q) 411 | return rep 412 | 413 | def c_decision_problem(np.ndarray[np.float64_t,ndim=2] P, np.ndarray[np.float64_t,ndim=2] Q,int p,int q, double eps): 414 | """ 415 | Usage 416 | ----- 417 | Test is the frechet distance between trajectories P and Q are inferior to eps 418 | 419 | Parameters 420 | ---------- 421 | param P : px2 numpy_array, Trajectory P 422 | param Q : qx2 numpy_array, Trajectory Q 423 | param p : float, number of points in Trajectory P 424 | param q : float, number of points in Trajectory Q 425 | param eps : float, reachability distance 426 | 427 | Returns 428 | ------- 429 | rep : bool, return true if frechet distance is inf to eps 430 | """ 431 | cdef dict LF,BF 432 | cdef bool rep 433 | 434 | LF,BF= _compute_LF_BF(P,Q,p,q,eps) 435 | rep,_,_ =_compute_LR_BR(LF,BF,p,q) 436 | return rep 437 | 438 | cdef list _compute_critical_values(np.ndarray[np.float64_t,ndim=2] P, np.ndarray[np.float64_t,ndim=2] Q,int p,int q): 439 | """ 440 | Usage 441 | ----- 442 | Compute all the critical values between trajectories P and Q 443 | 444 | Parameters 445 | ---------- 446 | param P : px2 numpy_array, Trajectory P 447 | param Q : qx2 numpy_array, Trajectory Q 448 | param p : float, number of points in Trajectory P 449 | param q : float, number of points in Trajectory Q 450 | 451 | Returns 452 | ------- 453 | cc : list, all critical values between trajectories P and Q 454 | """ 455 | cdef double origin,end,end_point,Lij,Bij 456 | cdef set cc 457 | cdef int i,j 458 | 459 | origin = c_eucl_dist(P[0,0],P[0,1],Q[0,0],Q[0,1]) 460 | end = c_eucl_dist(P[p-1,0],P[p-1,1],Q[q-1,0],Q[q-1,1]) 461 | end_point=fmax(origin,end) 462 | cc=set([end_point]) 463 | for i from 0 <= i < p-1: 464 | for j from 0 <= j < q-1: 465 | Lij=c_point_to_seg(Q[j,0],Q[j,1],P[i,0],P[i,1],P[i+1,0],P[i+1,1]) 466 | if Lij>end_point: 467 | cc.add(Lij) 468 | Bij=c_point_to_seg(P[i,0],P[i,1],Q[j,0],Q[j,1],Q[j+1,0],Q[j+1,1]) 469 | if Bij>end_point: 470 | cc.add(Bij) 471 | return sorted(list(cc)) 472 | 473 | def c_compute_critical_values(np.ndarray[np.float64_t,ndim=2] P, np.ndarray[np.float64_t,ndim=2] Q,int p,int q): 474 | """ 475 | Usage 476 | ----- 477 | Compute all the critical values between trajectories P and Q 478 | 479 | Parameters 480 | ---------- 481 | param P : px2 numpy_array, Trajectory P 482 | param Q : qx2 numpy_array, Trajectory Q 483 | param p : float, number of points in Trajectory P 484 | param q : float, number of points in Trajectory Q 485 | 486 | Returns 487 | ------- 488 | cc : list, all critical values between trajectories P and Q 489 | """ 490 | 491 | cdef double origin,end,end_point,Lij,Bij 492 | cdef set cc 493 | cdef int i,j 494 | 495 | origin = c_eucl_dist(P[0,0],P[0,1],Q[0,0],Q[0,1]) 496 | end = c_eucl_dist(P[p-1,0],P[p-1,1],Q[q-1,0],Q[q-1,1]) 497 | end_point=fmax(origin,end) 498 | cc=set([end_point]) 499 | for i from 0 <= i < p-1: 500 | for j from 0 <= j < q-1: 501 | Lij=c_point_to_seg(Q[j,0],Q[j,1],P[i,0],P[i,1],P[i+1,0],P[i+1,1]) 502 | if Lij>end_point: 503 | cc.add(Lij) 504 | Bij=c_point_to_seg(P[i,0],P[i,1],Q[j,0],Q[j,1],Q[j+1,0],Q[j+1,1]) 505 | if Bij>end_point: 506 | cc.add(Bij) 507 | return sorted(list(cc)) 508 | 509 | def c_frechet(np.ndarray[np.float64_t,ndim=2] P,np.ndarray[np.float64_t,ndim=2] Q): 510 | """ 511 | Usage 512 | ----- 513 | Compute the frechet distance between trajectories P and Q 514 | 515 | Parameters 516 | ---------- 517 | param P : px2 numpy_array, Trajectory P 518 | param Q : qx2 numpy_array, Trajectory Q 519 | 520 | Returns 521 | ------- 522 | frech : float, the frechet distance between trajectories P and Q 523 | """ 524 | 525 | cdef int p,q,m_i 526 | cdef double eps 527 | cdef bool rep 528 | cdef list cc 529 | p=len(P) 530 | q=len(Q) 531 | 532 | cc=_compute_critical_values(P,Q,p,q) 533 | eps=cc[0] 534 | while(len(cc)!=1): 535 | m_i=len(cc)/2-1 536 | eps = cc[m_i] 537 | rep = _decision_problem(P,Q,p,q,eps) 538 | if rep: 539 | cc=cc[:m_i+1] 540 | else: 541 | cc=cc[m_i+1:] 542 | return eps 543 | 544 | 545 | 546 | -------------------------------------------------------------------------------- /traj_dist/cydist/hausdorff.pyx: -------------------------------------------------------------------------------- 1 | STUFF = "Hi" 2 | 3 | from libc.math cimport fmax 4 | from libc.math cimport fmin 5 | 6 | cimport numpy as np 7 | 8 | from basic_euclidean import c_point_to_trajectory 9 | from basic_geographical import c_point_to_path 10 | 11 | ############# 12 | # Euclidean # 13 | ############# 14 | 15 | cdef double _e_directed_hausdorff ( np.ndarray[np.float64_t,ndim=2] t1,np.ndarray[np.float64_t,ndim=2] t2): 16 | """ 17 | Usage 18 | ----- 19 | directed hausdorff distance from trajectory t1 to trajectory t2. 20 | 21 | Parameters 22 | ---------- 23 | param t1 : len(t1)x2 numpy_array 24 | param t2 : len(t2)x2 numpy_array 25 | 26 | Returns 27 | ------- 28 | dh : float, directed hausdorff from trajectory t1 to trajectory t2 29 | """ 30 | cdef double dh 31 | cdef int n1,i 32 | 33 | dh=0.0 34 | n1 = len(t1) 35 | for i from 0 <= i < n1: 36 | dh=fmax(c_point_to_trajectory(t1[i,0],t1[i,1],t2),dh) 37 | return dh 38 | 39 | def c_e_directed_hausdorff ( np.ndarray[np.float64_t,ndim=2] t1,np.ndarray[np.float64_t,ndim=2] t2): 40 | """ 41 | Usage 42 | ----- 43 | directed hausdorff distance from trajectory t1 to trajectory t2. 44 | 45 | Parameters 46 | ---------- 47 | param t1 : len(t1)x2 numpy_array 48 | param t2 : len(t2)x2 numpy_array 49 | 50 | Returns 51 | ------- 52 | dh : float, directed hausdorff from trajectory t1 to trajectory t2 53 | """ 54 | cdef double dh 55 | cdef int n1,i 56 | 57 | dh=0.0 58 | n1 = len(t1) 59 | for i from 0 <= i < n1: 60 | dh=fmax(c_point_to_trajectory(t1[i,0],t1[i,1],t2),dh) 61 | return dh 62 | 63 | 64 | def c_e_hausdorff(np.ndarray[np.float64_t,ndim=2] t1,np.ndarray[np.float64_t,ndim=2] t2): 65 | """ 66 | Usage 67 | ----- 68 | hausdorff distance between trajectories t1 and t2. 69 | 70 | Parameters 71 | ---------- 72 | param t1 : len(t1)x2 numpy_array 73 | param t2 : len(t2)x2 numpy_array 74 | 75 | Returns 76 | ------- 77 | h : float, hausdorff from trajectories t1 and t2 78 | """ 79 | cdef double h 80 | 81 | h=fmax(_e_directed_hausdorff(t1,t2),_e_directed_hausdorff(t2,t1)) 82 | return h 83 | 84 | 85 | ################ 86 | # Geographical # 87 | ################ 88 | 89 | 90 | cdef double _g_directed_hausdorff ( np.ndarray[np.float64_t,ndim=2] t1,np.ndarray[np.float64_t,ndim=2] t2): 91 | """ 92 | Usage 93 | ----- 94 | directed hausdorff distance from trajectory t1 to trajectory t2. 95 | 96 | Parameters 97 | ---------- 98 | param t1 : len(t1)x2 numpy_array 99 | param t2 : len(t2)x2 numpy_array 100 | 101 | Returns 102 | ------- 103 | dh : float, directed hausdorff from trajectory t1 to trajectory t2 104 | """ 105 | cdef double dh,dist_k0 106 | cdef int n0,n1,i,j 107 | cdef np.ndarray[np.float64_t,ndim=1] lats0,lons0,lats1,lons1 108 | 109 | n1 = len(t2) 110 | n0 = len(t1) 111 | lats0=t1[:,1] 112 | lons0=t1[:,0] 113 | lats1=t2[:,1] 114 | lons1=t2[:,0] 115 | 116 | dh=0 117 | for j from 0 <= j < n1 : 118 | dist_j0=9e100 119 | for i from 0 <= i < (n0-1): 120 | dist_j0=fmin(dist_j0,c_point_to_path(lons0[i],lats0[i],lons0[i+1],lats0[i+1],lons1[j],lats1[j])) 121 | dh=fmax(dh,dist_j0) 122 | return dh 123 | 124 | def c_g_directed_hausdorff ( np.ndarray[np.float64_t,ndim=2] t1,np.ndarray[np.float64_t,ndim=2] t2): 125 | """ 126 | Usage 127 | ----- 128 | directed hausdorff distance from trajectory t1 to trajectory t2. 129 | 130 | Parameters 131 | ---------- 132 | param t1 : len(t1)x2 numpy_array 133 | param t2 : len(t2)x2 numpy_array 134 | 135 | Returns 136 | ------- 137 | dh : float, directed hausdorff from trajectory t1 to trajectory t2 138 | """ 139 | cdef double dh,dist_k0 140 | cdef int n0,n1,i,j 141 | cdef np.ndarray[np.float64_t,ndim=1] lats0,lons0,lats1,lons1 142 | 143 | n1 = len(t2) 144 | n0 = len(t1) 145 | lats0=t1[:,1] 146 | lons0=t1[:,0] 147 | lats1=t2[:,1] 148 | lons1=t2[:,0] 149 | 150 | dh=0 151 | for j from 0 <= j < n1 : 152 | dist_j0=9e100 153 | for i from 0 <= i < (n0-1): 154 | dist_j0=fmin(dist_j0,c_point_to_path(lons0[i],lats0[i],lons0[i+1],lats0[i+1],lons1[j],lats1[j])) 155 | dh=fmax(dh,dist_j0) 156 | return dh 157 | 158 | def c_g_hausdorff(np.ndarray[np.float64_t,ndim=2] t1,np.ndarray[np.float64_t,ndim=2] t2): 159 | """ 160 | Usage 161 | ----- 162 | hausdorff distance between trajectories t1 and t2. 163 | 164 | Parameters 165 | ---------- 166 | param t1 : len(t1)x2 numpy_array 167 | param t2 : len(t2)x2 numpy_array 168 | 169 | Returns 170 | ------- 171 | h : float, hausdorff from trajectories t1 and t2 172 | """ 173 | cdef double h 174 | 175 | h=fmax(_g_directed_hausdorff(t1,t2),_g_directed_hausdorff(t2,t1)) 176 | return h -------------------------------------------------------------------------------- /traj_dist/cydist/lcss.pyx: -------------------------------------------------------------------------------- 1 | STUFF = "Hi" 2 | 3 | from libc.math cimport fmax 4 | from libc.math cimport fmin 5 | 6 | 7 | cimport numpy as np 8 | import numpy as np 9 | 10 | 11 | from basic_euclidean import c_eucl_dist 12 | from basic_geographical import c_great_circle_distance 13 | 14 | def c_e_lcss(np.ndarray[np.float64_t,ndim=2] t0, np.ndarray[np.float64_t,ndim=2] t1, eps): 15 | """ 16 | Usage 17 | ----- 18 | The Longuest-Common-Subsequence distance between trajectory t0 and t1. 19 | 20 | Parameters 21 | ---------- 22 | param t0 : len(t0)x2 numpy_array 23 | param t1 : len(t1)x2 numpy_array 24 | eps : float 25 | 26 | Returns 27 | ------- 28 | lcss : float 29 | The Longuest-Common-Subsequence distance between trajectory t0 and t1 30 | """ 31 | cdef int n0,n1,i,j 32 | cdef np.ndarray[np.float64_t,ndim=2] C 33 | cdef double x0,y0,x1,y1,lcss 34 | 35 | n0 = len(t0)+1 36 | n1 = len(t1)+1 37 | 38 | # An (m+1) times (n+1) matrix 39 | C=np.zeros((n0,n1)) 40 | 41 | for i from 1 <= i < n0: 42 | for j from 1 <= j < n1: 43 | x0=t0[i-1,0] 44 | y0=t0[i-1,1] 45 | x1=t1[j-1,0] 46 | y1=t1[j-1,1] 47 | if c_eucl_dist(x0,y0,x1,y1) siei_norm_2 : 81 | md=_ordered_mixed_distance(sjx,sjy,ejx,ejy,six,siy,eix,eiy,sjejx,sjejy,sieix,sieiy,sjej_norm_2,siei_norm_2) 82 | else : 83 | md=_ordered_mixed_distance(six,siy,eix,eiy,sjx,sjy,ejx,ejy,sieix,sieiy,sjejx,sjejy,siei_norm_2,sjej_norm_2) 84 | 85 | return md 86 | 87 | def c_segments_distance(np.ndarray[np.float64_t,ndim=2] traj_0,np.ndarray[np.float64_t,ndim=2] traj_1): 88 | 89 | cdef np.ndarray[np.float64_t,ndim=2] M 90 | cdef int n0,n1,i,j 91 | 92 | 93 | n0=len(traj_0) 94 | n1=len(traj_1) 95 | M=np.zeros((n0-1,n1-1)) 96 | for i in range(n0-1): 97 | for j in range(n1-1): 98 | M[i,j]=_mixed_distance(traj_0[i,0],traj_0[i,1],traj_0[i+1,0],traj_0[i+1,1], 99 | traj_1[j,0],traj_1[j,1],traj_1[j+1,0],traj_1[j+1,1]) 100 | return M 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /traj_dist/cydist/sowd.pyx: -------------------------------------------------------------------------------- 1 | STUFF = "Hi" 2 | 3 | #cython: boundscheck=False 4 | #cython: wraparound=False 5 | 6 | cimport numpy as np 7 | import numpy as np 8 | from libc.stdlib cimport malloc, free 9 | 10 | from libc.math cimport fmin 11 | from basic_euclidean import c_eucl_dist 12 | from cpython cimport bool 13 | from numpy.math cimport INFINITY 14 | 15 | 16 | 17 | cdef double _owd_grid_brut(np.ndarray[long,ndim=2] traj_cell_1, np.ndarray[long,ndim=2] traj_cell_2): 18 | 19 | cdef double D,d 20 | cdef int n1,n2,p1x,p1y,p2x,p2y,i,j 21 | cdef np.ndarray[long,ndim=1] p1,p2 22 | 23 | D=0 24 | n1=len(traj_cell_1) 25 | n2=len(traj_cell_2) 26 | 27 | for i from 0 <= i < n1: 28 | p1=traj_cell_1[i] 29 | p1x=p1[0] 30 | p1y=p1[1] 31 | d=INFINITY 32 | for j from 0 <= j < n2: 33 | p2=traj_cell_2[j] 34 | p2x=p2[0] 35 | p2y=p2[1] 36 | d=fmin(d,c_eucl_dist(p1x,p1y,p2x,p2y)) 37 | D = D + d 38 | D = D/n1 39 | return D 40 | 41 | def c_owd_grid_brut(np.ndarray[long,ndim=2] traj_cell_1, np.ndarray[long,ndim=2] traj_cell_2): 42 | 43 | cdef double D,d 44 | cdef int n1,n2,p1x,p1y,p2x,p2y,i,j 45 | cdef np.ndarray[long,ndim=1] p1,p2 46 | 47 | D=0 48 | n1=len(traj_cell_1) 49 | n2=len(traj_cell_2) 50 | 51 | for i from 0 <= i < n1: 52 | p1=traj_cell_1[i] 53 | p1x=p1[0] 54 | p1y=p1[1] 55 | d=INFINITY 56 | for j from 0 <= j < n2: 57 | p2=traj_cell_2[j] 58 | p2x=p2[0] 59 | p2y=p2[1] 60 | d=fmin(d,c_eucl_dist(p1x,p1y,p2x,p2y)) 61 | D = D + d 62 | D = D/n1 63 | return D 64 | 65 | 66 | cdef double _sowd_grid_brut(np.ndarray[long,ndim=2] traj_cell_1,np.ndarray[long,ndim=2] traj_cell_2): 67 | 68 | cdef double sowd_brut_dist 69 | 70 | sowd_brut_dist = _owd_grid_brut(traj_cell_1,traj_cell_2)+_owd_grid_brut(traj_cell_2,traj_cell_1) 71 | return sowd_brut_dist/2 72 | 73 | def c_sowd_grid_brut(np.ndarray[long,ndim=2] traj_cell_1,np.ndarray[long,ndim=2] traj_cell_2): 74 | 75 | cdef double sowd_brut_dist 76 | 77 | sowd_brut_dist = _owd_grid_brut(traj_cell_1,traj_cell_2)+_owd_grid_brut(traj_cell_2,traj_cell_1) 78 | return sowd_brut_dist/2 79 | 80 | 81 | 82 | cdef np.ndarray[long,ndim=1] _find_first_min_points( np.ndarray[np.float64_t,ndim=1] pt, int n): 83 | 84 | cdef np.ndarray[np.uint8_t,ndim=1,cast=True] min_points 85 | cdef np.ndarray[long,ndim=1] min_points_index 86 | cdef double pti,ptip,ptim 87 | cdef bool m_p,ciip,cimi 88 | 89 | min_points = np.empty([n],dtype=bool) 90 | 91 | if n == 1: 92 | min_points[0] = True 93 | else: 94 | pti=pt[0] 95 | ptip=pt[1] 96 | ciip= pti < ptip 97 | min_points[0] = ciip 98 | for i from 1 <= i < n-1: 99 | pti = pt[i] 100 | ptip = pt[i+1] 101 | ptim = pt[i-1] 102 | ciip = pti < ptip 103 | cimi = pti < ptim 104 | m_p = (ciip and cimi) 105 | min_points [i] = m_p 106 | ptim = pt[n - 2] 107 | pti = pt[n - 1] 108 | cimi = pti < ptim 109 | min_points[n-1] = cimi 110 | 111 | min_points_index = np.where(np.array(min_points))[0] 112 | return min_points_index 113 | 114 | 115 | def c_find_first_min_points( np.ndarray[np.float64_t,ndim=1] pt, int n): 116 | 117 | cdef np.ndarray[np.uint8_t,ndim=1,cast=True] min_points 118 | cdef np.ndarray[long,ndim=1] min_points_index 119 | cdef double pti,ptip,ptim 120 | cdef bool m_p,ciip,cimi 121 | 122 | min_points = np.empty([n],dtype=bool) 123 | 124 | if n == 1: 125 | min_points[0] = True 126 | else: 127 | pti=pt[0] 128 | ptip=pt[1] 129 | ciip= pti < ptip 130 | min_points[0] = ciip 131 | for i from 1 <= i < n-1: 132 | pti = pt[i] 133 | ptip = pt[i+1] 134 | ptim = pt[i-1] 135 | ciip = pti < ptip 136 | cimi = pti < ptim 137 | m_p = (ciip and cimi) 138 | min_points [i] = m_p 139 | ptim = pt[n - 2] 140 | pti = pt[n - 1] 141 | cimi = pti < ptim 142 | min_points[n-1] = cimi 143 | 144 | min_points_index = np.where(np.array(min_points))[0] 145 | return min_points_index 146 | 147 | 148 | def c_owd_grid( np.ndarray[long,ndim=2] traj_cell_1,np.ndarray[long,ndim=2] traj_cell_2): 149 | 150 | cdef int n1,n2,px,py,p_precx,p_precy,p2x,p2y,i,j,n_S_old,ig,pgx,pgy,rmin,rmax,pgpx,pgpy,pgpmx,pgpmy,pgppx,pgppy 151 | cdef double dpp2,D,d,dist,dist_back,dist_forw 152 | cdef np.ndarray[long,ndim=1] p,p_prec,pg,p2,S_old,pgp,pgpp,pgpm,S_ind 153 | cdef np.ndarray[np.float64_t,ndim=1] p_t2 154 | 155 | n1 = len(traj_cell_1) 156 | n2 = len(traj_cell_2) 157 | 158 | p = traj_cell_1[0] 159 | px = p[0] 160 | py = p[1] 161 | 162 | p2 = traj_cell_2[0] 163 | p2x=p2[0] 164 | p2y=p2[1] 165 | 166 | p_t2 = np.empty([n2],dtype=float) 167 | dpp2=c_eucl_dist(px,py,p2x,p2y) 168 | p_t2[0] = dpp2 169 | for i from 1 <= i < n2: 170 | p2 = traj_cell_2[i] 171 | p2x=p2[0] 172 | p2y=p2[1] 173 | dpp2_=c_eucl_dist(px,py,p2x,p2y) 174 | dpp2=fmin(dpp2,dpp2_) 175 | p_t2[i] = dpp2_ 176 | 177 | S_old = _find_first_min_points(p_t2, n2) 178 | D = dpp2 179 | for i from 1 <= i < n1: 180 | p_prec = p 181 | p_precx=px 182 | p_precy=py 183 | p = traj_cell_1[i] 184 | px=p[0] 185 | py=p[1] 186 | S_ind = np.zeros([n2],dtype=int) 187 | d = INFINITY 188 | n_S_old=len(S_old) 189 | for j from 0 <= j < n_S_old: 190 | ig = S_old[j] 191 | pg = traj_cell_2[ig] 192 | pgx=pg[0] 193 | pgy=pg[1] 194 | if (p_precy == py and pgx != p_precx) or (p_precx == px and pgy != p_precy): 195 | S_ind[ig] = 1 196 | dppg=c_eucl_dist(px,py,pgx,pgy) 197 | d=fmin(d,dppg) 198 | else: 199 | if j == 0: 200 | if n_S_old == 1 : 201 | rmin = 0 202 | rmax = n2 203 | else: 204 | rmin = 0 205 | rmax = S_old[j+1] 206 | elif j == n_S_old - 1: 207 | rmin = S_old[j-1] 208 | rmax = n2 209 | else: 210 | rmin=S_old[j-1]+1 211 | rmax= S_old[j+1] 212 | for igp from rmin <= igp < rmax: 213 | pgp = traj_cell_2[igp] 214 | pgpx = pgp[0] 215 | pgpy = pgp[1] 216 | if (p_precy == py and pgpx == px ) or (p_precx == px and pgpy == py) or igp==ig : 217 | if igp !=0: 218 | pgpm = traj_cell_2[igp-1] 219 | pgpmx=pgpm[0] 220 | pgpmy=pgpm[1] 221 | dist_back=c_eucl_dist(pgpmx,pgpmy,px,py) 222 | else: 223 | dist_back = INFINITY 224 | if igp !=n2-1: 225 | pgpp = traj_cell_2[igp+1] 226 | pgppx=pgpp[0] 227 | pgppy=pgpp[1] 228 | dist_forw=c_eucl_dist(pgppx,pgppy,px,py) 229 | else: 230 | dist_forw = INFINITY 231 | dist = c_eucl_dist(pgpx,pgpy,px,py) 232 | if dist < dist_back and dist < dist_forw: 233 | if not S_ind[igp]: 234 | S_ind[igp] = 1 235 | d=fmin(d,dist) 236 | 237 | S_old=np.where(S_ind)[0] 238 | D += d 239 | return D/n1 240 | 241 | 242 | cdef double _owd_grid( np.ndarray[long,ndim=2] traj_cell_1,np.ndarray[long,ndim=2] traj_cell_2): 243 | 244 | cdef int n1,n2,px,py,p_precx,p_precy,p2x,p2y,i,j,n_S_old,ig,pgx,pgy,rmin,rmax,pgpx,pgpy,pgpmx,pgpmy,pgppx,pgppy 245 | cdef double dpp2,D,d,dist,dist_back,dist_forw 246 | cdef np.ndarray[long,ndim=1] p,p_prec,pg,p2,S_old,pgp,pgpp,pgpm,S_ind 247 | cdef np.ndarray[np.float64_t,ndim=1] p_t2 248 | 249 | n1 = len(traj_cell_1) 250 | n2 = len(traj_cell_2) 251 | 252 | p = traj_cell_1[0] 253 | px = p[0] 254 | py = p[1] 255 | 256 | p2 = traj_cell_2[0] 257 | p2x=p2[0] 258 | p2y=p2[1] 259 | 260 | p_t2 = np.empty([n2],dtype=float) 261 | dpp2=c_eucl_dist(px,py,p2x,p2y) 262 | p_t2[0] = dpp2 263 | for i from 1 <= i < n2: 264 | p2 = traj_cell_2[i] 265 | p2x=p2[0] 266 | p2y=p2[1] 267 | dpp2_=c_eucl_dist(px,py,p2x,p2y) 268 | dpp2=fmin(dpp2,dpp2_) 269 | p_t2[i] = dpp2_ 270 | 271 | S_old = _find_first_min_points(p_t2, n2) 272 | D = dpp2 273 | for i from 1 <= i < n1: 274 | p_prec = p 275 | p_precx=px 276 | p_precy=py 277 | p = traj_cell_1[i] 278 | px=p[0] 279 | py=p[1] 280 | S_ind = np.zeros([n2],dtype=int) 281 | d = INFINITY 282 | n_S_old=len(S_old) 283 | for j from 0 <= j < n_S_old: 284 | ig = S_old[j] 285 | pg = traj_cell_2[ig] 286 | pgx=pg[0] 287 | pgy=pg[1] 288 | if (p_precy == py and pgx != p_precx) or (p_precx == px and pgy != p_precy): 289 | S_ind[ig] = 1 290 | dppg=c_eucl_dist(px,py,pgx,pgy) 291 | d=fmin(d,dppg) 292 | else: 293 | if j == 0: 294 | if n_S_old == 1 : 295 | rmin = 0 296 | rmax = n2 297 | else: 298 | rmin = 0 299 | rmax = S_old[j+1] 300 | elif j == n_S_old - 1: 301 | rmin = S_old[j-1] 302 | rmax = n2 303 | else: 304 | rmin=S_old[j-1]+1 305 | rmax= S_old[j+1] 306 | for igp from rmin <= igp < rmax: 307 | pgp = traj_cell_2[igp] 308 | pgpx = pgp[0] 309 | pgpy = pgp[1] 310 | if (p_precy == py and pgpx == px ) or (p_precx == px and pgpy == py) or igp==ig : 311 | if igp !=0: 312 | pgpm = traj_cell_2[igp-1] 313 | pgpmx=pgpm[0] 314 | pgpmy=pgpm[1] 315 | dist_back=c_eucl_dist(pgpmx,pgpmy,px,py) 316 | else: 317 | dist_back = INFINITY 318 | if igp !=n2-1: 319 | pgpp = traj_cell_2[igp+1] 320 | pgppx=pgpp[0] 321 | pgppy=pgpp[1] 322 | dist_forw=c_eucl_dist(pgppx,pgppy,px,py) 323 | else: 324 | dist_forw = INFINITY 325 | dist = c_eucl_dist(pgpx,pgpy,px,py) 326 | if dist < dist_back and dist < dist_forw: 327 | if not S_ind[igp]: 328 | S_ind[igp] = 1 329 | d=fmin(d,dist) 330 | 331 | S_old=np.where(S_ind)[0] 332 | D += d 333 | return D/n1 334 | 335 | 336 | 337 | cdef double _sowd_grid(np.ndarray[long,ndim=2] traj_cell_1,np.ndarray[long,ndim=2] traj_cell_2): 338 | 339 | cdef double sowd_dist 340 | 341 | sowd_dist = _owd_grid(traj_cell_1,traj_cell_2)+_owd_grid(traj_cell_2,traj_cell_1) 342 | return sowd_dist/2 343 | 344 | def c_sowd_grid(np.ndarray[long,ndim=2] traj_cell_1,np.ndarray[long,ndim=2] traj_cell_2): 345 | 346 | cdef double sowd_dist 347 | 348 | sowd_dist = _owd_grid(traj_cell_1,traj_cell_2)+_owd_grid(traj_cell_2,traj_cell_1) 349 | return sowd_dist/2 -------------------------------------------------------------------------------- /traj_dist/cydist/sspd.pyx: -------------------------------------------------------------------------------- 1 | STUFF = "Hi" 2 | 3 | #cython: boundscheck=False 4 | #cython: wraparound=False 5 | 6 | from libc.math cimport fmin 7 | 8 | from basic_euclidean import c_point_to_trajectory 9 | from basic_geographical import c_point_to_path 10 | cimport numpy as np 11 | from numpy.math cimport INFINITY 12 | 13 | 14 | 15 | ################ 16 | ## Euclidean ### 17 | ################ 18 | 19 | cdef double _e_spd (np.ndarray[np.float64_t,ndim=2] t1, np.ndarray[np.float64_t,ndim=2] t2): 20 | """ 21 | Usage 22 | ----- 23 | The spd-distance of trajectory t2 from trajectory t1 24 | The spd-distance is the sum of the all the point-to-trajectory distance of points of t1 from trajectory t2 25 | 26 | Parameters 27 | ---------- 28 | param t1 : len(t1)x2 numpy_array 29 | param t2 : len(t2)x2 numpy_array 30 | 31 | Returns 32 | ------- 33 | spd : float 34 | spd-distance of trajectory t2 from trajectory t1 35 | """ 36 | cdef int nt,i 37 | cdef double spd,px,py 38 | 39 | nt=len(t1) 40 | spd=0 41 | for i from 0 <= i < (nt): 42 | px=t1[i,0] 43 | py=t1[i,1] 44 | spd=spd+c_point_to_trajectory(px,py,t2) 45 | spd=spd/nt 46 | return spd 47 | 48 | def c_e_spd (np.ndarray[np.float64_t,ndim=2] t1, np.ndarray[np.float64_t,ndim=2] t2): 49 | """ 50 | Usage 51 | ----- 52 | The spd-distance of trajectory t2 from trajectory t1 53 | The spd-distance is the sum of the all the point-to-trajectory distance of points of t1 from trajectory t2 54 | 55 | Parameters 56 | ---------- 57 | param t1 : len(t1)x2 numpy_array 58 | param t2 : len(t2)x2 numpy_array 59 | 60 | Returns 61 | ------- 62 | spd : float 63 | spd-distance of trajectory t2 from trajectory t1 64 | """ 65 | cdef int nt,i 66 | cdef double spd,px,py 67 | 68 | nt=len(t1) 69 | spd=0 70 | for i from 0 <= i < (nt): 71 | px=t1[i,0] 72 | py=t1[i,1] 73 | spd=spd+c_point_to_trajectory(px,py,t2) 74 | spd=spd/nt 75 | return spd 76 | 77 | def c_e_sspd (np.ndarray[np.float64_t,ndim=2] t1, np.ndarray[np.float64_t,ndim=2] t2): 78 | """ 79 | Usage 80 | ----- 81 | The sspd-distance between trajectories t1 and t2. 82 | The sspd-distance is the mean of the spd-distance between of t1 from t2 and the spd-distance of t2 from t1. 83 | 84 | Parameters 85 | ---------- 86 | param t1 : len(t1)x2 numpy_array 87 | param t2 : len(t2)x2 numpy_array 88 | 89 | Returns 90 | ------- 91 | sspd : float 92 | sspd-distance of trajectory t2 from trajectory t1 93 | """ 94 | cdef double sspd 95 | sspd=(_e_spd(t1,t2) + _e_spd(t2,t1))/2 96 | return sspd 97 | 98 | 99 | ################### 100 | ## Geographical ### 101 | ################### 102 | 103 | cdef double _g_spd(np.ndarray[np.float64_t,ndim=2] t1, np.ndarray[np.float64_t,ndim=2] t2): 104 | """ 105 | Usage 106 | ----- 107 | The spd-distance of trajectory t2 from trajectory t1 108 | The spd-distance is the sum of the all the point-to-path distance of points of t1 from trajectory t2 109 | 110 | Parameters 111 | ---------- 112 | param t1 : len(t1)x2 numpy_array 113 | param t2 : len(t2)x2 numpy_array 114 | 115 | Returns 116 | ------- 117 | spd : float 118 | spd-distance of trajectory t2 from trajectory t1 119 | """ 120 | cdef int n1,i,j 121 | cdef double dist,dist_j0 122 | cdef np.ndarray[np.float64_t,ndim=1] lats0,lons0,lats1,lons1 123 | 124 | n0=len(t1) 125 | n1=len(t2) 126 | lats0=t1[:,1] 127 | lons0=t1[:,0] 128 | lats1=t2[:,1] 129 | lons1=t2[:,0] 130 | dist=0 131 | for j from 0 <= j < n1 : 132 | dist_j0=INFINITY 133 | for i from 0 <= i < (n0-1): 134 | dist_j0=fmin(dist_j0,c_point_to_path(lons0[i],lats0[i],lons0[i+1],lats0[i+1],lons1[j],lats1[j])) 135 | dist=dist+dist_j0 136 | dist=float(dist)/n1 137 | return dist 138 | 139 | 140 | def c_g_spd(np.ndarray[np.float64_t,ndim=2] t1, np.ndarray[np.float64_t,ndim=2] t2): 141 | """ 142 | Usage 143 | ----- 144 | The spd-distance of trajectory t2 from trajectory t1 145 | The spd-distance is the sum of the all the point-to-path distance of points of t1 from trajectory t2 146 | 147 | Parameters 148 | ---------- 149 | param t1 : len(t1)x2 numpy_array 150 | param t2 : len(t2)x2 numpy_array 151 | 152 | Returns 153 | ------- 154 | spd : float 155 | spd-distance of trajectory t2 from trajectory t1 156 | """ 157 | cdef int n1,i,j 158 | cdef double dist,dist_j0 159 | cdef np.ndarray[np.float64_t,ndim=1] lats0,lons0,lats1,lons1 160 | 161 | n0=len(t1) 162 | n1=len(t2) 163 | lats0=t1[:,1] 164 | lons0=t1[:,0] 165 | lats1=t2[:,1] 166 | lons1=t2[:,0] 167 | dist=0 168 | for j from 0 <= j < n1: 169 | dist_j0=INFINITY 170 | for i from 0 <= i < (n0-1): 171 | dist_j0=fmin(dist_j0,c_point_to_path(lons0[i],lats0[i],lons0[i+1],lats0[i+1],lons1[j],lats1[j])) 172 | dist=dist+dist_j0 173 | dist=float(dist)/n1 174 | return dist 175 | 176 | 177 | cdef double _g_sspd(np.ndarray[np.float64_t,ndim=2] t1, np.ndarray[np.float64_t,ndim=2] t2): 178 | """ 179 | Usage 180 | ----- 181 | The sspd-distance between trajectories t1 and t2. 182 | The sspd-distance is the mean of the spd-distance between of t1 from t2 and the spd-distance of t2 from t1. 183 | 184 | Parameters 185 | ---------- 186 | param t1 : len(t1)x2 numpy_array 187 | param t2 : len(t2)x2 numpy_array 188 | 189 | 190 | Returns 191 | ------- 192 | sspd : float 193 | sspd-distance of trajectory t2 from trajectory t1 194 | """ 195 | 196 | cdef double dist 197 | 198 | dist=_g_spd(t1,t2) + _g_spd(t2,t1) 199 | return dist 200 | 201 | def c_g_sspd(np.ndarray[np.float64_t,ndim=2] t1, np.ndarray[np.float64_t,ndim=2] t2): 202 | """ 203 | Usage 204 | ----- 205 | The sspd-distance between trajectories t1 and t2. 206 | The sspd-distance is the mean of the spd-distance between of t1 from t2 and the spd-distance of t2 from t1. 207 | 208 | Parameters 209 | ---------- 210 | param t1 : len(t1)x2 numpy_array 211 | param t2 : len(t2)x2 numpy_array 212 | 213 | Returns 214 | ------- 215 | sspd : float 216 | sspd-distance of trajectory t2 from trajectory t1 217 | """ 218 | dist=_g_spd(t1,t2) + _g_spd(t2,t1) 219 | return dist 220 | -------------------------------------------------------------------------------- /traj_dist/distance.py: -------------------------------------------------------------------------------- 1 | from pydist.linecell import trajectory_set_grid 2 | 3 | from pydist.sspd import e_sspd, g_sspd 4 | from pydist.dtw import e_dtw, g_dtw 5 | from pydist.erp import e_erp, g_erp 6 | from pydist.edr import e_edr, g_edr 7 | from pydist.lcss import e_lcss, g_lcss 8 | from pydist.frechet import frechet 9 | from pydist.discret_frechet import discret_frechet 10 | from pydist.hausdorff import e_hausdorff, g_hausdorff 11 | from pydist.sowd import sowd_grid 12 | 13 | from cydist.sspd import c_e_sspd, c_g_sspd 14 | from cydist.dtw import c_e_dtw, c_g_dtw 15 | from cydist.erp import c_e_erp, c_g_erp 16 | from cydist.edr import c_e_edr, c_g_edr 17 | from cydist.lcss import c_e_lcss, c_g_lcss 18 | from cydist.hausdorff import c_e_hausdorff, c_g_hausdorff 19 | from cydist.discret_frechet import c_discret_frechet 20 | from cydist.frechet import c_frechet 21 | from cydist.sowd import c_sowd_grid 22 | 23 | import numpy as np 24 | 25 | import warnings 26 | 27 | __all__ = ["pdist","cdist", "sspd", "sowd_grid", "frechet", "discret_frechet", "hausdorff", "dtw", "lcss", "edr", "erp"] 28 | 29 | METRIC_DIC = {"geographical": {"cython": {"sspd": c_g_sspd, 30 | "dtw": c_g_dtw, 31 | "lcss": c_g_lcss, 32 | "hausdorff":c_g_hausdorff, 33 | "sowd_grid": c_sowd_grid, 34 | "erp" : c_g_erp, 35 | "edr" : c_g_edr }, 36 | "python": {"sspd": g_sspd, 37 | "dtw": g_dtw, 38 | "lcss": g_lcss, 39 | "hausdorff":g_hausdorff, 40 | "sowd_grid": sowd_grid, 41 | "erp" : g_erp, 42 | "edr" : g_edr }}, 43 | "euclidean": {"cython": {"sspd": c_e_sspd, 44 | "dtw": c_e_dtw, 45 | "lcss": c_e_lcss, 46 | "hausdorff":c_e_hausdorff, 47 | "discret_frechet": c_discret_frechet, 48 | "frechet": c_frechet, 49 | "sowd_grid": c_sowd_grid, 50 | "erp": c_e_erp, 51 | "edr": c_e_edr }, 52 | "python": {"sspd": e_sspd, 53 | "dtw": e_dtw, 54 | "lcss": e_lcss, 55 | "hausdorff": e_hausdorff, 56 | "discret_frechet": discret_frechet, 57 | "frechet": frechet, 58 | "sowd_grid":sowd_grid, 59 | "erp" : e_erp, 60 | "edr" : e_edr }}} 61 | 62 | 63 | # ################# 64 | # Simple Distance # 65 | # ################# 66 | 67 | def sspd(traj_1, traj_2, type_d = "euclidean", implementation = "auto"): 68 | """ 69 | Usage 70 | ----- 71 | Compute the Symmetrized Segment-Path Distance between trajectory traj_1 and traj_2 72 | 73 | type_d's parameters available are "euclidean" or "geographical". 74 | - "euclidean" can handle every trajectory dimensions. 75 | - "geographical" implies a 2-dimensional trajectory where first dimensions is longitudes coordinate and second 76 | dimension is latitute coordinate. 77 | 78 | If the distance traj_0 and traj_1 are 2-dimensional, the cython implementation is used, otherwised the python one 79 | is used, unless "python" implementation is specified 80 | 81 | 82 | Parameters 83 | ---------- 84 | 85 | param traj_1 : a 2-D numpry array 86 | param traj_2 : a 2-D numpry array 87 | param type_d : string, distance type_d used (geographical or euclidean) 88 | param implementation : string, implementation used (python, cython, auto) 89 | 90 | Returns 91 | ------- 92 | 93 | dist : a float. The sspd distance between traj_1 and traj_2 94 | """ 95 | dim_1= traj_1.shape[1] 96 | dim_2= traj_2.shape[1] 97 | 98 | if dim_1 != dim_2: 99 | raise ValueError("Trajectories should have same dimensions. %d and %d given" %(dim_1,dim_2)) 100 | dim = dim_1 101 | 102 | if not (type_d in ["geographical", "euclidean"]): 103 | raise ValueError("The type_d argument should be 'euclidean' or 'geographical'\ntype_d given is : " + type_d) 104 | 105 | if not (implementation in ["cython", "python", "auto"]): 106 | raise ValueError("The implementation argument should be 'cython', 'python' or 'auto'\n implementation given " 107 | "is : " + implementation) 108 | if dim!=2 and implementation == "cython": 109 | raise ValueError("Implementation with cython is disponible only with 2-dimension trajectories, " 110 | "not %d-dimension" %dim) 111 | if dim!=2 and implementation == "geographical": 112 | raise ValueError("Geographical distance implies 2-dimension trajectories, " 113 | "not %d-dimension" %dim) 114 | if implementation =="auto": 115 | if dim == 2: 116 | implementation = "cython" 117 | else: 118 | implementation = "python" 119 | 120 | dist_func = METRIC_DIC[type_d][implementation]["sspd"] 121 | dist = dist_func(traj_1, traj_2) 122 | return dist 123 | 124 | 125 | def sowd_grid(traj_1, traj_2, type_d = "euclidean", implementation = "auto", converted = None, precision=None): 126 | """ 127 | Usage 128 | ----- 129 | Compute the Symmetrized One_Way Distance between trajectory traj_1 and traj_2 130 | 131 | type_d's parameters available are "euclidean" or "geographical". 132 | - "euclidean" can handle every trajectory dimensions. 133 | - "geographical" implies a 2-dimensional trajectory where first dimensions is longitudes coordinate and second 134 | dimension is latitute coordinate. 135 | 136 | If the distance traj_0 and traj_1 are 2-dimensional, the cython implementation is used, otherwised the python one 137 | is used, unless "python" implementation is specified 138 | 139 | 'sowd_grid' computes distance between trajectory in grid representation. If the coordinate 140 | are geographical, this conversion can be made according to the geohash encoding. If so, the geohash 'precision' 141 | is needed. Otherwise trajectory are considered encoded in cells representation 142 | 143 | 144 | Parameters 145 | ---------- 146 | 147 | param traj_1: : a 2-D numpry array 148 | param traj_2: : a 2-D numpry array 149 | param type_d : : string, distance type_d used (geographical or euclidean) 150 | param implementation : string, implementation used (python, cython, auto) 151 | param converted : Boolean, if True trajectories are considered in cells representation 152 | param precision : Geohash precisions for conversion 153 | 154 | Returns 155 | ------- 156 | 157 | dist : a float. The sowd_grid distance between traj_1 and traj_2 158 | """ 159 | dim_1= traj_1.shape[1] 160 | dim_2= traj_2.shape[1] 161 | 162 | if dim_1 != dim_2: 163 | raise ValueError("Trajectories should have same dimensions. %d and %d given" %(dim_1,dim_2)) 164 | dim = dim_1 165 | 166 | if not (type_d in ["geographical", "euclidean"]): 167 | raise ValueError("The type_d argument should be 'euclidean' or 'geographical'\ntype_d given is : " + type_d) 168 | 169 | if not (implementation in ["cython", "python", "auto"]): 170 | raise ValueError("The implementation argument should be 'cython', 'python' or 'auto'\n implementation given " 171 | "is : " + implementation) 172 | if type_d == "euclidean" and not(converted): 173 | raise Warning("Euclidean implementation for distance sowd_grid is not " 174 | "disponible if your data is not already converted in cell format") 175 | if dim!=2 and implementation == "cython": 176 | raise ValueError("Implementation with cython is disponible only with 2-dimension trajectories, " 177 | "not %d-dimension" %dim) 178 | if dim!=2 and implementation == "geographical": 179 | raise ValueError("Geographical distance implies 2-dimension trajectories, " 180 | "not %d-dimension" %dim) 181 | 182 | if implementation =="auto": 183 | if dim == 2: 184 | implementation = "cython" 185 | else: 186 | implementation = "python" 187 | 188 | if converted is None: 189 | warnings.warn("converted parameter should be specified for metric sowd_grid. Default " 190 | "is True") 191 | converted = True 192 | if converted: 193 | cells_list=[traj_1, traj_2] 194 | else: 195 | if precision is None: 196 | warnings.warn("precision parameter should be specified for metric sowd_grid if converted " 197 | "is False. Default is 7") 198 | precision = 7 199 | print("Cells conversion start") 200 | cells_list_, _, _, _, _ =trajectory_set_grid([traj_1, traj_2],precision) 201 | cells_list = [np.array(cells_list_[0])[:,:2],np.array(cells_list_[1])[:,:2]] 202 | print("Cells conversion ok") 203 | 204 | dist_func = METRIC_DIC[type_d][implementation]["sowd_grid"] 205 | dist = dist_func(cells_list[0], cells_list[1]) 206 | return dist 207 | 208 | 209 | def frechet(traj_1, traj_2, type_d = "euclidean", implementation = "auto"): 210 | """ 211 | Usage 212 | ----- 213 | Compute the Frechet Distance between trajectory traj_1 and traj_2 214 | 215 | type_d's parameter available is "euclidean". 216 | 217 | If the distance traj_0 and traj_1 are 2-dimensional, the cython implementation is used, otherwised the python one 218 | is used, unless "python" implementation is specified 219 | 220 | 221 | Parameters 222 | ---------- 223 | 224 | param traj_1 : a 2-D numpry array 225 | param traj_2 : a 2-D numpry array 226 | param type_d : string, distance type_d used (geographical or euclidean) 227 | param implementation : string, implementation used (python, cython, auto) 228 | 229 | Returns 230 | ------- 231 | 232 | dist : a float. The frechet distance between traj_1 and traj_2 233 | """ 234 | dim_1= traj_1.shape[1] 235 | dim_2= traj_2.shape[1] 236 | 237 | if dim_1 != dim_2: 238 | raise ValueError("Trajectories should have same dimensions. %d and %d given" %(dim_1,dim_2)) 239 | dim = dim_1 240 | 241 | if type_d != "euclidean": 242 | raise ValueError("The type_d argument should be 'euclidean'\ntype_d given is : " + type_d) 243 | 244 | if not (implementation in ["cython", "python", "auto"]): 245 | raise ValueError("The implementation argument should be 'cython', 'python' or 'auto'\n implementation given " 246 | "is : " + implementation) 247 | if dim!=2 and implementation == "cython": 248 | raise ValueError("Implementation with cython is disponible only with 2-dimension trajectories, " 249 | "not %d-dimension" %dim) 250 | 251 | if implementation =="auto": 252 | if dim == 2: 253 | implementation = "cython" 254 | else: 255 | implementation = "python" 256 | 257 | dist_func = METRIC_DIC[type_d][implementation]["frechet"] 258 | dist = dist_func(traj_1, traj_2) 259 | return dist 260 | 261 | 262 | def discret_frechet(traj_1, traj_2, type_d = "euclidean", implementation = "auto"): 263 | """ 264 | Usage 265 | ----- 266 | Compute the Discrete Frechet Distance between trajectory traj_1 and traj_2 267 | 268 | type_d's parameter available is "euclidean". 269 | 270 | If the distance traj_0 and traj_1 are 2-dimensional, the cython implementation is used, otherwised the python one 271 | is used, unless "python" implementation is specified 272 | 273 | 274 | Parameters 275 | ---------- 276 | 277 | param traj_1 : a 2-D numpry array 278 | param traj_2 : a 2-D numpry array 279 | param type_d : string, distance type_d used (geographical or euclidean) 280 | param implementation : string, implementation used (python, cython, auto) 281 | 282 | Returns 283 | ------- 284 | 285 | dist : a float. The discret_frechet distance between traj_1 and traj_2 286 | """ 287 | dim_1= traj_1.shape[1] 288 | dim_2= traj_2.shape[1] 289 | 290 | if dim_1 != dim_2: 291 | raise ValueError("Trajectories should have same dimensions. %d and %d given" %(dim_1,dim_2)) 292 | dim = dim_1 293 | 294 | if type_d != "euclidean": 295 | raise ValueError("The type_d argument should be 'euclidean'\ntype_d given is : " + type_d) 296 | 297 | if not (implementation in ["cython", "python", "auto"]): 298 | raise ValueError("The implementation argument should be 'cython', 'python' or 'auto'\n implementation given " 299 | "is : " + implementation) 300 | if dim!=2 and implementation == "cython": 301 | raise ValueError("Implementation with cython is disponible only with 2-dimension trajectories, " 302 | "not %d-dimension" %dim) 303 | 304 | if implementation =="auto": 305 | if dim == 2: 306 | implementation = "cython" 307 | else: 308 | implementation = "python" 309 | 310 | dist_func = METRIC_DIC[type_d][implementation]["discret_frechet"] 311 | dist = dist_func(traj_1, traj_2) 312 | return dist 313 | 314 | 315 | def hausdorff(traj_1, traj_2, type_d = "euclidean", implementation = "auto"): 316 | """ 317 | Usage 318 | ----- 319 | Compute the Hausdorff Distance between trajectory traj_1 and traj_2 320 | 321 | type_d's parameters available are "euclidean" or "geographical". 322 | - "euclidean" can handle every trajectory dimensions. 323 | - "geographical" implies a 2-dimensional trajectory where first dimensions is longitudes coordinate and second 324 | dimension is latitute coordinate. 325 | 326 | If the distance traj_0 and traj_1 are 2-dimensional, the cython implementation is used, otherwised the python one 327 | is used, unless "python" implementation is specified 328 | 329 | 330 | Parameters 331 | ---------- 332 | 333 | param traj_1 : a 2-D numpry array 334 | param traj_2 : a 2-D numpry array 335 | param type_d : string, distance type_d used (geographical or euclidean) 336 | param implementation : string, implementation used (python, cython, auto) 337 | 338 | Returns 339 | ------- 340 | 341 | dist : a float. The hausdorff distance between traj_1 and traj_2 342 | """ 343 | dim_1= traj_1.shape[1] 344 | dim_2= traj_2.shape[1] 345 | 346 | if dim_1 != dim_2: 347 | raise ValueError("Trajectories should have same dimensions. %d and %d given" %(dim_1,dim_2)) 348 | dim = dim_1 349 | 350 | if not (type_d in ["geographical", "euclidean"]): 351 | raise ValueError("The type_d argument should be 'euclidean' or 'geographical'\ntype_d given is : " + type_d) 352 | 353 | if not (implementation in ["cython", "python", "auto"]): 354 | raise ValueError("The implementation argument should be 'cython', 'python' or 'auto'\n implementation given " 355 | "is : " + implementation) 356 | if dim!=2 and implementation == "cython": 357 | raise ValueError("Implementation with cython is disponible only with 2-dimension trajectories, " 358 | "not %d-dimension" %dim) 359 | if dim!=2 and implementation == "geographical": 360 | raise ValueError("Geographical distance implies 2-dimension trajectories, " 361 | "not %d-dimension" %dim) 362 | if implementation =="auto": 363 | if dim == 2: 364 | implementation = "cython" 365 | else: 366 | implementation = "python" 367 | 368 | dist_func = METRIC_DIC[type_d][implementation]["hausdorff"] 369 | dist = dist_func(traj_1, traj_2) 370 | return dist 371 | 372 | 373 | def dtw(traj_1, traj_2, type_d = "euclidean", implementation = "auto"): 374 | """ 375 | Usage 376 | ----- 377 | Compute the Dynamic Time Warping Distance between trajectory traj_1 and traj_2 378 | 379 | type_d's parameters available are "euclidean" or "geographical". 380 | - "euclidean" can handle every trajectory dimensions. 381 | - "geographical" implies a 2-dimensional trajectory where first dimensions is longitudes coordinate and second 382 | dimension is latitute coordinate. 383 | 384 | If the distance traj_0 and traj_1 are 2-dimensional, the cython implementation is used, otherwised the python one 385 | is used, unless "python" implementation is specified 386 | 387 | 388 | Parameters 389 | ---------- 390 | 391 | param traj_1 : a 2-D numpry array 392 | param traj_2 : a 2-D numpry array 393 | param type_d : string, distance type_d used (geographical or euclidean) 394 | param implementation : string, implementation used (python, cython, auto) 395 | 396 | Returns 397 | ------- 398 | 399 | dist : a float. The dtw distance between traj_1 and traj_2 400 | """ 401 | dim_1= traj_1.shape[1] 402 | dim_2= traj_2.shape[1] 403 | 404 | if dim_1 != dim_2: 405 | raise ValueError("Trajectories should have same dimensions. %d and %d given" %(dim_1,dim_2)) 406 | dim = dim_1 407 | 408 | if not (type_d in ["geographical", "euclidean"]): 409 | raise ValueError("The type_d argument should be 'euclidean' or 'geographical'\ntype_d given is : " + type_d) 410 | 411 | if not (implementation in ["cython", "python", "auto"]): 412 | raise ValueError("The implementation argument should be 'cython', 'python' or 'auto'\n implementation given " 413 | "is : " + implementation) 414 | if dim!=2 and implementation == "cython": 415 | raise ValueError("Implementation with cython is disponible only with 2-dimension trajectories, " 416 | "not %d-dimension" %dim) 417 | if dim!=2 and implementation == "geographical": 418 | raise ValueError("Geographical distance implies 2-dimension trajectories, " 419 | "not %d-dimension" %dim) 420 | if implementation =="auto": 421 | if dim == 2: 422 | implementation = "cython" 423 | else: 424 | implementation = "python" 425 | 426 | dist_func = METRIC_DIC[type_d][implementation]["dtw"] 427 | dist = dist_func(traj_1, traj_2) 428 | return dist 429 | 430 | 431 | def lcss(traj_1, traj_2, type_d = "euclidean", implementation = "auto", eps=200): 432 | """ 433 | Usage 434 | ----- 435 | Compute the Longuest Common Subsequence Distance between trajectory traj_1 and traj_2 436 | 437 | type_d's parameters available are "euclidean" or "geographical". 438 | - "euclidean" can handle every trajectory dimensions. 439 | - "geographical" implies a 2-dimensional trajectory where first dimensions is longitudes coordinate and second 440 | dimension is latitute coordinate. 441 | 442 | If the distance traj_0 and traj_1 are 2-dimensional, the cython implementation is used, otherwised the python one 443 | is used, unless "python" implementation is specified 444 | 445 | 446 | Parameters 447 | ---------- 448 | 449 | param traj_1 : a 2-D numpry array 450 | param traj_2 : a 2-D numpry array 451 | param type_d : string, distance type_d used (geographical or euclidean) 452 | param implementation : string, implementation used (python, cython, auto) 453 | 454 | Returns 455 | ------- 456 | 457 | dist : a float. The lcss distance between traj_1 and traj_2 458 | """ 459 | dim_1= traj_1.shape[1] 460 | dim_2= traj_2.shape[1] 461 | 462 | if dim_1 != dim_2: 463 | raise ValueError("Trajectories should have same dimensions. %d and %d given" %(dim_1,dim_2)) 464 | dim = dim_1 465 | 466 | if not (type_d in ["geographical", "euclidean"]): 467 | raise ValueError("The type_d argument should be 'euclidean' or 'geographical'\ntype_d given is : " + type_d) 468 | 469 | if not (implementation in ["cython", "python", "auto"]): 470 | raise ValueError("The implementation argument should be 'cython', 'python' or 'auto'\n implementation given " 471 | "is : " + implementation) 472 | if dim!=2 and implementation == "cython": 473 | raise ValueError("Implementation with cython is disponible only with 2-dimension trajectories, " 474 | "not %d-dimension" %dim) 475 | if dim!=2 and implementation == "geographical": 476 | raise ValueError("Geographical distance implies 2-dimension trajectories, " 477 | "not %d-dimension" %dim) 478 | if implementation =="auto": 479 | if dim == 2: 480 | implementation = "cython" 481 | else: 482 | implementation = "python" 483 | 484 | dist_func = METRIC_DIC[type_d][implementation]["lcss"] 485 | dist = dist_func(traj_1, traj_2, eps) 486 | return dist 487 | 488 | 489 | def edr(traj_1, traj_2, type_d = "euclidean", implementation = "auto", eps = 200): 490 | """ 491 | Usage 492 | ----- 493 | Compute the Edit distance on Real Sequence between trajectory traj_1 and traj_2 494 | 495 | type_d's parameters available are "euclidean" or "geographical". 496 | - "euclidean" can handle every trajectory dimensions. 497 | - "geographical" implies a 2-dimensional trajectory where first dimensions is longitudes coordinate and second 498 | dimension is latitute coordinate. 499 | 500 | If the distance traj_0 and traj_1 are 2-dimensional, the cython implementation is used, otherwised the python one 501 | is used, unless "python" implementation is specified 502 | 503 | 504 | Parameters 505 | ---------- 506 | 507 | param traj_1 : a 2-D numpry array 508 | param traj_2 : a 2-D numpry array 509 | param type_d : string, distance type_d used (geographical or euclidean) 510 | param implementation : string, implementation used (python, cython, auto) 511 | 512 | Returns 513 | ------- 514 | 515 | dist : a float. The edr distance between traj_1 and traj_2 516 | """ 517 | dim_1= traj_1.shape[1] 518 | dim_2= traj_2.shape[1] 519 | 520 | if dim_1 != dim_2: 521 | raise ValueError("Trajectories should have same dimensions. %d and %d given" %(dim_1,dim_2)) 522 | dim = dim_1 523 | 524 | if not (type_d in ["geographical", "euclidean"]): 525 | raise ValueError("The type_d argument should be 'euclidean' or 'geographical'\ntype_d given is : " + type_d) 526 | 527 | if not (implementation in ["cython", "python", "auto"]): 528 | raise ValueError("The implementation argument should be 'cython', 'python' or 'auto'\n implementation given " 529 | "is : " + implementation) 530 | if dim!=2 and implementation == "cython": 531 | raise ValueError("Implementation with cython is disponible only with 2-dimension trajectories, " 532 | "not %d-dimension" %dim) 533 | if dim!=2 and implementation == "geographical": 534 | raise ValueError("Geographical distance implies 2-dimension trajectories, " 535 | "not %d-dimension" %dim) 536 | if implementation =="auto": 537 | if dim == 2: 538 | implementation = "cython" 539 | else: 540 | implementation = "python" 541 | 542 | dist_func = METRIC_DIC[type_d][implementation]["edr"] 543 | dist = dist_func(traj_1, traj_2, eps) 544 | return dist 545 | 546 | 547 | def erp(traj_1, traj_2, type_d = "euclidean", implementation = "auto", g = None): 548 | """ 549 | Usage 550 | ----- 551 | Compute theEdit Distance on Real Sequence between trajectory traj_1 and traj_2 552 | 553 | type_d's parameters available are "euclidean" or "geographical". 554 | - "euclidean" can handle every trajectory dimensions. 555 | - "geographical" implies a 2-dimensional trajectory where first dimensions is longitudes coordinate and second 556 | dimension is latitute coordinate. 557 | 558 | If the distance traj_0 and traj_1 are 2-dimensional, the cython implementation is used, otherwised the python one 559 | is used, unless "python" implementation is specified 560 | 561 | 562 | Parameters 563 | ---------- 564 | 565 | param traj_1 : a 2-D numpry array 566 | param traj_2 : a 2-D numpry array 567 | param type_d : string, distance type_d used (geographical or euclidean) 568 | param implementation : string, implementation used (python, cython, auto) 569 | 570 | Returns 571 | ------- 572 | 573 | dist : a float. The erp distance between traj_1 and traj_2 574 | """ 575 | dim_1= traj_1.shape[1] 576 | dim_2= traj_2.shape[1] 577 | 578 | if dim_1 != dim_2: 579 | raise ValueError("Trajectories should have same dimensions. %d and %d given" %(dim_1,dim_2)) 580 | dim = dim_1 581 | 582 | if g is None: 583 | g = np.zeros(dim,dtype=float) 584 | warnings.warn("g parameter should be specified for metric erp. Default is ") 585 | print(g) 586 | else: 587 | if g.shape[0]!= dim : 588 | raise ValueError("g and trajectories in list should have same dimension") 589 | 590 | if not (type_d in ["geographical", "euclidean"]): 591 | raise ValueError("The type_d argument should be 'euclidean' or 'geographical'\ntype_d given is : " + type_d) 592 | 593 | if not (implementation in ["cython", "python", "auto"]): 594 | raise ValueError("The implementation argument should be 'cython', 'python' or 'auto'\n implementation given " 595 | "is : " + implementation) 596 | if dim!=2 and implementation == "cython": 597 | raise ValueError("Implementation with cython is disponible only with 2-dimension trajectories, " 598 | "not %d-dimension" %dim) 599 | if dim!=2 and implementation == "geographical": 600 | raise ValueError("Geographical distance implies 2-dimension trajectories, " 601 | "not %d-dimension" %dim) 602 | if implementation =="auto": 603 | if dim == 2: 604 | implementation = "cython" 605 | else: 606 | implementation = "python" 607 | 608 | dist_func = METRIC_DIC[type_d][implementation]["erp"] 609 | dist = dist_func(traj_1, traj_2, g) 610 | return dist 611 | 612 | 613 | 614 | 615 | 616 | 617 | # #################### 618 | # Pairwise Distance # 619 | # #################### 620 | 621 | def pdist(traj_list, metric="sspd", type_d="euclidean", implementation="auto", converted = None, precision = None, 622 | eps= None, g = None ): 623 | """ 624 | Usage 625 | ----- 626 | Pairwise distances between trajectory in traj_list. 627 | 628 | metrics available are : 629 | 630 | 1. 'sspd' 631 | 632 | Computes the distances using the Symmetrized Segment Path distance. 633 | 634 | 2. 'dtw' 635 | 636 | Computes the distances using the Dynamic Path Warping distance. 637 | 638 | 3. 'lcss' 639 | 640 | Computes the distances using the Longuest Common SubSequence distance 641 | 642 | 4. 'hausdorf' 643 | 644 | Computes the distances using the Hausdorff distance. 645 | 646 | 5. 'frechet' 647 | 648 | Computes the distances using the Frechet distance. 649 | 650 | 6. 'discret_frechet' 651 | 652 | Computes the distances using the Discrete Frechet distance. 653 | 654 | 7. 'sowd_grid' 655 | 656 | Computes the distances using the Symmetrized One Way Distance. 657 | 658 | 8. 'erp' 659 | 660 | Computes the distances using the Edit Distance with real Penalty. 661 | 662 | 9. 'edr' 663 | 664 | Computes the distances using the Edit Distance on Real sequence. 665 | 666 | type_d available are "euclidean" or "geographical". Some distance can be computing according to geographical space 667 | instead of euclidean. If so, traj_0 and traj_1 have to be 2-dimensional. First column is longitude, second one 668 | is latitude. 669 | 670 | If the distance traj_0 and traj_1 are 2-dimensional, the cython implementation is used else the python one is used. 671 | unless "python" implementation is specified 672 | 673 | 'sowd_grid' computes distance between trajectory in grid representation. If the coordinate 674 | are geographical, this conversion can be made according to the geohash encoding. If so, the geohash 'precision' 675 | is needed. 676 | 677 | 'edr' and 'lcss' require 'eps' parameter. These distance assume that two locations are similar, or not, according 678 | to a given threshold, eps. 679 | 680 | 'erp' require g parameter. This distance require a gap parameter. Which must have same dimension that the 681 | trajectory. 682 | 683 | Parameters 684 | ---------- 685 | 686 | param traj_list: a list of nT numpy array trajectory 687 | param metric : string, distance used 688 | param type_d : string, distance type_d used (geographical or euclidean) 689 | param implementation : string, implementation used (python, cython, auto) 690 | param converted : boolean, specified if the data are converted in cell format (sowd_grid 691 | metric) 692 | param precision : int, precision of geohash (sowd_grid ) 693 | param eps : float, threshold distance (edr and lcss) 694 | param g : numpy arrays, gaps (erp distance) 695 | 696 | 697 | Returns 698 | ------- 699 | 700 | M : a nT x nT numpy array. Where the i,j entry is the distance between traj_list[i] and traj_list[j] 701 | """ 702 | 703 | 704 | list_dim = map(lambda x: x.shape[1] if len(x.shape)>1 else 1, traj_list) 705 | nb_traj = len(traj_list) 706 | if not (len(set(list_dim)) == 1): 707 | raise ValueError("All trajectories must have same dimesion !") 708 | dim= list_dim[0] 709 | 710 | if not (metric in ["sspd", "dtw", "lcss", "hausdorff", "frechet", "discret_frechet", "sowd_grid", 711 | "erp", "edr"]): 712 | raise ValueError("The metric argument should be 'sspd', 'dtw', 'lcss','erp','edr' 'hausdorff', 'frechet'," 713 | "'discret_frechet' or 'sowd_grid' \nmetric given is : " + metric) 714 | 715 | if not (type_d in ["geographical", "euclidean"]): 716 | raise ValueError("The type_d argument should be 'euclidean' or 'geographical'\ntype_d given is : " + type_d) 717 | 718 | if not (implementation in ["cython", "python", "auto"]): 719 | raise ValueError("The implementation argument should be 'cython', 'python' or 'auto'\n implementation given " 720 | "is : " + implementation) 721 | 722 | if type_d == "geographical" and (metric in ["frechet", "discret_frechet"]): 723 | raise ValueError("Geographical implementation for distance "+metric+" is not " 724 | "disponible") 725 | if type_d == "euclidean" and (metric in ["sowd","sowd_grid"]): 726 | if not(converted): 727 | raise ValueError("Euclidean implementation for distance "+metric+" is not " 728 | "disponible if your data is not already converted in cell format") 729 | if dim!=2 and implementation == "cython": 730 | raise ValueError("Implementation with cython is disponible only with 2-dimension trajectories, " 731 | "not %d-dimension" %dim) 732 | if dim!=2 and implementation == "geographical": 733 | raise ValueError("Geographical distance implies 2-dimension trajectories, " 734 | "not %d-dimension" %dim) 735 | 736 | if implementation =="auto": 737 | if dim == 2: 738 | implementation = "cython" 739 | else: 740 | implementation = "python" 741 | 742 | print("Computing " + type_d + " distance " + metric + " with implementation " + implementation + " for %d trajectories" % nb_traj) 743 | M = np.zeros(sum(range(nb_traj))) 744 | dist = METRIC_DIC[type_d][implementation][metric] 745 | if metric.startswith("sowd_grid"): 746 | if converted is None: 747 | warnings.warn("converted parameter should be specified for metric sowd_grid. Default " 748 | "is True") 749 | converted = True 750 | if converted: 751 | cells_list=traj_list 752 | else: 753 | if precision is None: 754 | warnings.warn("precision parameter should be specified for metric sowd_grid if converted " 755 | "is False. Default is 7") 756 | precision = 7 757 | print("Cells conversion start") 758 | cells_list_, _, _, _, _ =trajectory_set_grid(traj_list,precision) 759 | cells_list = map(lambda x : np.array(x)[:,:2],cells_list_) 760 | print("Cells conversion ok") 761 | im = 0 762 | for i in range(nb_traj): 763 | cells_list_i=cells_list[i] 764 | for j in range(i + 1, nb_traj): 765 | cells_list_j=cells_list[j] 766 | M[im] = dist(cells_list_i, cells_list_j) 767 | im+=1 768 | elif metric == "erp": 769 | if g is None: 770 | g = np.zeros(dim,dtype=float) 771 | warnings.warn("g parameter should be specified for metric erp. Default is ") 772 | print(g) 773 | else: 774 | if g.shape[0]!= dim : 775 | raise ValueError("g and trajectories in list should have same dimension") 776 | im = 0 777 | for i in range(nb_traj): 778 | traj_list_i = traj_list[i] 779 | for j in range(i + 1, nb_traj): 780 | traj_list_j = traj_list[j] 781 | M[im] = dist(traj_list_i, traj_list_j,g) 782 | im+=1 783 | elif metric == "lcss" or metric == "edr": 784 | if eps is None: 785 | warnings.warn("eps parameter should be specified for metric 'lcss' and 'edr', default is 100 ") 786 | eps=100 787 | im = 0 788 | for i in range(nb_traj): 789 | traj_list_i = traj_list[i] 790 | for j in range(i + 1, nb_traj): 791 | traj_list_j = traj_list[j] 792 | M[im] = dist(traj_list_i, traj_list_j,eps) 793 | im+=1 794 | else: 795 | im=0 796 | for i in range(nb_traj): 797 | traj_list_i = traj_list[i] 798 | for j in range(i + 1, nb_traj): 799 | traj_list_j = traj_list[j] 800 | M[im] = dist(traj_list_i, traj_list_j) 801 | im+=1 802 | return M 803 | 804 | # ######################## 805 | # Distance between list # 806 | # ######################## 807 | 808 | def cdist(traj_list_1, traj_list_2, metric="sspd", type_d="euclidean", implementation="auto", converted = None, precision = None, 809 | eps= None, g = None ): 810 | """ 811 | Usage 812 | ----- 813 | Computes distance between each pair of the two list of trajectories 814 | 815 | metrics available are : 816 | 817 | 1. 'sspd' 818 | 819 | Computes the distances using the Symmetrized Segment Path distance. 820 | 821 | 2. 'dtw' 822 | 823 | Computes the distances using the Dynamic Path Warping distance. 824 | 825 | 3. 'lcss' 826 | 827 | Computes the distances using the Longuest Common SubSequence distance 828 | 829 | 4. 'hausdorf' 830 | 831 | Computes the distances using the Hausdorff distance. 832 | 833 | 5. 'frechet' 834 | 835 | Computes the distances using the Frechet distance. 836 | 837 | 6. 'discret_frechet' 838 | 839 | Computes the distances using the Discrete Frechet distance. 840 | 841 | 7. 'sowd_grid' 842 | 843 | Computes the distances using the Symmetrized One Way Distance. 844 | 845 | 8. 'erp' 846 | 847 | Computes the distances using the Edit Distance with real Penalty. 848 | 849 | 9. 'edr' 850 | 851 | Computes the distances using the Edit Distance on Real sequence. 852 | 853 | type_d available are "euclidean" or "geographical". Some distance can be computing according to geographical space 854 | instead of euclidean. If so, traj_0 and traj_1 have to be 2-dimensional. First column is longitude, second one 855 | is latitude. 856 | 857 | If the distance traj_0 and traj_1 are 2-dimensional, the cython implementation is used else the python one is used. 858 | unless "python" implementation is specified 859 | 860 | 'sowd_grid', compute distance between trajectory in grid representation. If the coordinate 861 | are geographical, this conversion can be made according to the geohash encoding. If so, the geohash 'precision' 862 | is needed. 863 | 864 | 'edr' and 'lcss' require 'eps' parameter. These distance assume that two locations are similar, or not, according 865 | to a given threshold, eps. 866 | 867 | 'erp' require g parameter. This distance require a gap parameter. Which must have same dimension that the 868 | trajectory. 869 | 870 | Parameters 871 | ---------- 872 | 873 | param traj_list: a list of nT numpy array trajectory 874 | param metric : string, distance used 875 | param type_d : string, distance type_d used (geographical or euclidean) 876 | param implementation : string, implementation used (python, cython, auto) 877 | param converted : boolean, specified if the data are converted in cell format (sowd_grid) 878 | metric) 879 | param precision : int, precision of geohash (sowd_grid) 880 | param eps : float, threshold distance (edr and lcss) 881 | param g : numpy arrays, gaps (erp distance) 882 | 883 | 884 | Returns 885 | ------- 886 | 887 | M : a nT1 x nT2 numpy array. Where the i,j entry is the distance between traj_list_1[i] and traj_list_2[j] 888 | 889 | """ 890 | 891 | list_dim_1 = map(lambda x: x.shape[1], traj_list_1) 892 | nb_traj_1 = len(traj_list_1) 893 | list_dim_2 = map(lambda x: x.shape[1], traj_list_2) 894 | nb_traj_2 = len(traj_list_2) 895 | if not (len(set(list_dim_1 + list_dim_2)) == 1): 896 | raise ValueError("All trajectories must have same dimesion !") 897 | dim= list_dim_1[0] 898 | 899 | if not (metric in ["sspd", "dtw", "lcss", "hausdorff", "frechet", "discret_frechet", "sowd_grid", 900 | "erp", "edr"]): 901 | raise ValueError("The metric argument should be 'sspd', 'dtw', 'lcss','erp','edr' 'hausdorff', 'frechet'," 902 | "'discret_frechet' or 'sowd_grid'\nmetric given is : " + metric) 903 | 904 | if not (type_d in ["geographical", "euclidean"]): 905 | raise ValueError("The type_d argument should be 'euclidean' or 'geographical'\ntype_d given is : " + type_d) 906 | 907 | if not (implementation in ["cython", "python", "auto"]): 908 | raise ValueError("The implementation argument should be 'cython', 'python' or 'auto'\n implementation given " 909 | "is : " + implementation) 910 | 911 | if type_d == "geographical" and (metric in ["frechet", "discret_frechet"]): 912 | raise ValueError("Geographical implementation for distance "+metric+" is not " 913 | "disponible") 914 | if type_d == "euclidean" and (metric in ["sowd","sowd_grid"]): 915 | if not(converted): 916 | raise ValueError("Euclidean implementation for distance "+metric+" is not " 917 | "disponible if your data is not already converted in cell format") 918 | if dim!=2 and implementation == "cython": 919 | raise ValueError("Implementation with cython is disponible only with 2-dimension trajectories, " 920 | "not %d-dimension" %dim) 921 | 922 | if implementation =="auto": 923 | if dim == 2: 924 | implementation = "cython" 925 | else: 926 | implementation = "python" 927 | 928 | print("Computing " + type_d + " distance " + metric + " with implementation " + implementation + " for %d and %d " 929 | "trajectories" % 930 | (nb_traj_1,nb_traj_2)) 931 | M = np.zeros((nb_traj_1, nb_traj_2)) 932 | dist = METRIC_DIC[type_d][implementation][metric] 933 | if metric.startswith("sowd_grid"): 934 | if converted is None: 935 | warnings.warn("converted parameter should be specified for metric sowd_grid. Default " 936 | "is True") 937 | converted = True 938 | if converted: 939 | cells_list_1=traj_list_1 940 | cells_list_2=traj_list_2 941 | else: 942 | if precision is None: 943 | warnings.warn("precision parameter should be specified for metric sowd_grid if converted " 944 | "is False. Default is 7") 945 | precision = 7 946 | cells_list, _, _, _, _ =trajectory_set_grid(traj_list_1+traj_list_2,precision) 947 | cells_list_1 = map(lambda x : np.array(x)[:,:2],cells_list[:nb_traj_1]) 948 | cells_list_2 = map(lambda x : np.array(x)[:,:2],cells_list[nb_traj_1:]) 949 | for i in range(nb_traj_1): 950 | cells_list_1_i = cells_list_1[i] 951 | for j in range(nb_traj_2): 952 | cells_list_2_j = cells_list_2[j] 953 | M[i, j] = dist(cells_list_1_i, cells_list_2_j) 954 | elif metric == "erp": 955 | if g is None: 956 | g = np.zeros(dim,dtype=float) 957 | warnings.warn("g parameter should be specified for metric erp. Default is ") 958 | print(g) 959 | else: 960 | if g.shape[0]!= dim : 961 | raise ValueError("g and trajectories in list should have same dimension") 962 | for i in range(nb_traj_1): 963 | traj_list_1_i = traj_list_1[i] 964 | for j in range(nb_traj_2): 965 | traj_list_2_j = traj_list_2[j] 966 | M[i, j] = dist(traj_list_1_i, traj_list_2_j,g) 967 | elif metric == "lcss" or metric == "edr": 968 | if eps is None: 969 | warnings.warn("eps parameter should be specified for metric 'lcss' and 'edr', default is 100 ") 970 | eps=100 971 | for i in range(nb_traj_1): 972 | traj_list_1_i = traj_list_1[i] 973 | for j in range(nb_traj_2): 974 | traj_list_2_j = traj_list_2[j] 975 | M[i, j] = dist(traj_list_1_i, traj_list_2_j,eps) 976 | else: 977 | for i in range(nb_traj_1): 978 | traj_list_1_i = traj_list_1[i] 979 | for j in range(nb_traj_2): 980 | traj_list_2_j = traj_list_2[j] 981 | M[i, j] = dist(traj_list_1_i, traj_list_2_j) 982 | return M 983 | -------------------------------------------------------------------------------- /traj_dist/example.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | # Three 2-D Trajectory 4 | traj_A = np.array([[-122.39534, 37.77678],[-122.3992 , 37.77631],[-122.40235, 37.77594],[-122.40553, 37.77848], 5 | [-122.40801, 37.78043],[-122.40837, 37.78066],[-122.41103, 37.78463],[-122.41207, 37.78954], 6 | [-122.41252, 37.79232],[-122.41316, 37.7951 ],[-122.41392, 37.7989 ],[-122.41435, 37.80129], 7 | [-122.41434, 37.80129]]) 8 | traj_B = np.array([[-122.39472, 37.77672],[-122.3946 , 37.77679],[-122.39314, 37.77846],[-122.39566, 37.78113], 9 | [-122.39978, 37.78438],[-122.40301, 37.78708],[-122.4048 , 37.78666],[-122.40584, 37.78564], 10 | [-122.40826, 37.78385],[-122.41061, 37.78321],[-122.41252, 37.78299]]) 11 | traj_C = np.array([[-122.39542, 37.77665],[-122.3988 , 37.77417],[-122.41042, 37.76944],[-122.41459, 37.77016], 12 | [-122.41462, 37.77013]]) 13 | traj_list = [traj_A, traj_B, traj_C] 14 | 15 | import traj_dist.distance as tdist 16 | 17 | # Simple distance 18 | 19 | dist = tdist.sspd(traj_A,traj_B) 20 | print(dist) 21 | 22 | # Pairwise distance 23 | 24 | pdist = tdist.pdist(traj_list,metric="sspd") 25 | print(pdist) 26 | 27 | # Distance between two list of trajectories 28 | 29 | cdist = tdist.cdist(traj_list, traj_list,metric="sspd") 30 | print(cdist) 31 | -------------------------------------------------------------------------------- /traj_dist/pydist/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'bguillouet' 2 | -------------------------------------------------------------------------------- /traj_dist/pydist/__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/pydist/__init__.pyc -------------------------------------------------------------------------------- /traj_dist/pydist/basic_euclidean.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math 3 | 4 | def eucl_dist(x,y): 5 | """ 6 | Usage 7 | ----- 8 | L2-norm between point x and y 9 | 10 | Parameters 11 | ---------- 12 | param x : numpy_array 13 | param y : numpy_array 14 | 15 | Returns 16 | ------- 17 | dist : float 18 | L2-norm between x and y 19 | """ 20 | dist = np.linalg.norm(x-y) 21 | return dist 22 | 23 | def point_to_seg(p,s1,s2): 24 | """ 25 | Usage 26 | ----- 27 | Point to segment distance between point p and segment delimited by s1 and s2 28 | 29 | Parameters 30 | ---------- 31 | param p : 1x2 numpy_array 32 | param s1 : 1x2 numpy_array 33 | param s2 : 1x2 numpy_array 34 | 35 | Returns 36 | ------- 37 | dpl: float 38 | Point to segment distance between p and s 39 | """ 40 | px = p[0] 41 | py = p[1] 42 | p1x = s1[0] 43 | p1y = s1[1] 44 | p2x = s2[0] 45 | p2y = s2[1] 46 | if p1x==p2x and p1y==p2y: 47 | dpl=eucl_dist(p,s1) 48 | else: 49 | segl= eucl_dist(s1,s2) 50 | u1 = (((px - p1x) * (p2x - p1x)) + ((py - p1y) * (p2y - p1y))) 51 | u = u1 / (segl * segl) 52 | 53 | if (u < 0.00001) or (u > 1): 54 | #// closest point does not fall within the line segment, take the shorter distance 55 | #// to an endpoint 56 | ix = eucl_dist(p,s1) 57 | iy = eucl_dist(p, s2) 58 | if ix > iy: 59 | dpl = iy 60 | else: 61 | dpl = ix 62 | else: 63 | # Intersecting point is on the line, use the formula 64 | ix = p1x + u * (p2x - p1x) 65 | iy = p1y + u * (p2y - p1y) 66 | dpl = eucl_dist(p, np.array([ix, iy])) 67 | 68 | return dpl 69 | 70 | def point_to_trajectory (p, t): 71 | """ 72 | Usage 73 | ----- 74 | Point-to-trajectory distance between point p and the trajectory t. 75 | The Point to trajectory distance is the minimum of point-to-segment distance between p and all segment s of t 76 | 77 | Parameters 78 | ---------- 79 | param p: 1x2 numpy_array 80 | param t : len(t)x2 numpy_array 81 | 82 | Returns 83 | ------- 84 | dpt : float, 85 | Point-to-trajectory distance between p and trajectory t 86 | """ 87 | dpt=min(map(lambda s1,s2 : point_to_seg(p,s1,s2), t[:-1],t[1:] )) 88 | return dpt 89 | 90 | 91 | def circle_line_intersection(px,py,s1x,s1y,s2x,s2y,eps): 92 | """ 93 | Usage 94 | ----- 95 | Find the intersections between the circle of radius eps and center (px, py) and the line delimited by points 96 | (s1x, s1y) and (s2x, s2y). 97 | It is supposed here that the intersection between them exists. If no, raise error 98 | 99 | Parameters 100 | ---------- 101 | param px : float, centre's abscissa of the circle 102 | param py : float, centre's ordinate of the circle 103 | param eps : float, radius of the circle 104 | param s1x : abscissa of the first point of the line 105 | param s1y : ordinate of the first point of the line 106 | param s2x : abscissa of the second point of the line 107 | param s2y : ordinate of the second point of the line 108 | 109 | Returns 110 | ------- 111 | intersect : 2x2 numpy_array 112 | Coordinate of the two intersections. 113 | If the two intersections are the same, that's means that the line is a tangent of the circle. 114 | """ 115 | if s2x==s1x : 116 | rac=math.sqrt((eps*eps) - ((s1x-px)*(s1x-px))) 117 | y1 = py+rac 118 | y2 = py-rac 119 | intersect = np.array([[s1x,y1],[s1x,y2]]) 120 | else: 121 | m= (s2y-s1y)/(s2x-s1x) 122 | c= s2y-m*s2x 123 | A=m*m+1 124 | B=2*(m*c-m*py-px) 125 | C=py*py-eps*eps+px*px-2*c*py+c*c 126 | delta=B*B-4*A*C 127 | if delta <= 0 : 128 | x = -B/(2*A) 129 | y = m*x+c 130 | intersect = np.array([[x,y],[x,y]]) 131 | elif delta > 0 : 132 | sdelta = math.sqrt(delta) 133 | x1= (-B+sdelta)/(2*A) 134 | y1=m*x1+c 135 | x2= (-B-sdelta)/(2*A) 136 | y2=m*x2+c 137 | intersect = np.array([[x1,y1],[x2,y2]]) 138 | else : 139 | raise ValueError("The intersection between circle and line is supposed to exist") 140 | return intersect 141 | -------------------------------------------------------------------------------- /traj_dist/pydist/basic_euclidean.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/pydist/basic_euclidean.pyc -------------------------------------------------------------------------------- /traj_dist/pydist/basic_geographical.py: -------------------------------------------------------------------------------- 1 | import math 2 | import numpy as np 3 | rad = math.pi / 180.0 4 | R = 6378137.0 5 | 6 | 7 | 8 | def great_circle_distance(lon1, lat1, lon2, lat2): 9 | """ 10 | Usage 11 | ----- 12 | Compute the great circle distance, in meter, between (lon1,lat1) and (lon2,lat2) 13 | 14 | Parameters 15 | ---------- 16 | param lat1: float, latitude of the first point 17 | param lon1: float, longitude of the first point 18 | param lat2: float, latitude of the second point 19 | param lon2: float, longitude of the second point 20 | 21 | Returns 22 | ------- 23 | d: float 24 | Great circle distance between (lon1,lat1) and (lon2,lat2) 25 | """ 26 | 27 | dlat = rad * (lat2 - lat1) 28 | dlon = rad * (lon2 - lon1) 29 | a = (math.sin(dlat / 2.0) * math.sin(dlat / 2.0) + 30 | math.cos(rad * lat1) * math.cos(rad * lat2) * 31 | math.sin(dlon / 2.0) * math.sin(dlon / 2.0)) 32 | c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a)) 33 | d = R * c 34 | return d 35 | 36 | 37 | def initial_bearing(lon1, lat1, lon2, lat2): 38 | """ 39 | Usage 40 | ----- 41 | Bearing between (lon1,lat1) and (lon2,lat2), in degree. 42 | 43 | Parameters 44 | ---------- 45 | param lat1: float, latitude of the first point 46 | param lon1: float, longitude of the first point 47 | param lat2: float, latitude of the second point 48 | param lon2: float, longitude of the second point 49 | 50 | Returns 51 | ------- 52 | brng: float 53 | Bearing between (lon1,lat1) and (lon2,lat2), in degree. 54 | 55 | """ 56 | dlon = rad * (lon2 - lon1) 57 | y = math.sin(dlon) * math.cos(rad * (lat2)) 58 | x = math.cos(rad * (lat1)) * math.sin(rad * (lat2)) - math.sin(rad * (lat1)) * math.cos(rad * (lat2)) * math.cos( 59 | dlon) 60 | ibrng = math.atan2(y, x) 61 | 62 | return ibrng 63 | 64 | 65 | def cross_track_distance(lon1, lat1, lon2, lat2, lon3, lat3): 66 | """ 67 | Usage 68 | ----- 69 | Angular cross-track-distance of a point (lon3, lat3) from a great-circle path between (lon1, lat1) and (lon2, lat2) 70 | The sign of this distance tells which side of the path the third point is on. 71 | 72 | Parameters : 73 | ---------- 74 | param lat1: float, latitude of the first point 75 | param lon1: float, longitude of the first point 76 | param lat2: float, latitude of the second point 77 | param lon2: float, longitude of the second point 78 | param lat3: float, latitude of the third point 79 | param lon3: float, longitude of the third point 80 | 81 | Usage 82 | ----- 83 | crt: float 84 | the (angular) cross_track_distance 85 | 86 | """ 87 | 88 | d13 = great_circle_distance(lon1, lat1, lon3, lat3) # distance from start point to third point 89 | theta13 = initial_bearing(lon1, lat1, lon3, lat3) # bearing from start point to third point 90 | theta12 = initial_bearing(lon1, lat1, lon2, lat2) # bearing from start point to end point 91 | 92 | crt = math.asin(math.sin(d13 / R) * math.sin(theta13 - theta12)) * R 93 | 94 | return crt 95 | 96 | 97 | def along_track_distance(crt, lon1, lat1, lon3, lat3): 98 | """ 99 | Usage 100 | ----- 101 | The along-track distance from the start point (lon1, lat1) to the closest point on the the path 102 | to the third point (lon3, lat3). 103 | 104 | Parameters 105 | ---------- 106 | param lat1: float, latitude of the first point 107 | param lon1: float, longitude of the first point 108 | param lat3: float, latitude of the third point 109 | param lon3: float, longitude of the third point 110 | param crt : float, cross_track_distance 111 | 112 | Returns 113 | ------- 114 | alt: float 115 | The along-track distance 116 | """ 117 | 118 | d13 = great_circle_distance(lon1, lat1, lon3, lat3) 119 | alt = math.acos(math.cos(d13 / R) / math.cos(crt / R)) * R 120 | return alt 121 | 122 | 123 | def point_to_path(lon1, lat1, lon2, lat2, lon3, lat3): 124 | """ 125 | Usage 126 | ----- 127 | The point-to-path distance between point (lon3, lat3) and path delimited by (lon1, lat1) and (lon2, lat2). 128 | The point-to-path distance is the cross_track distance between the great circle path if the projection of 129 | the third point lies on the path. If it is not on the path, return the minimum of the 130 | great_circle_distance between the first and the third or the second and the third point. 131 | 132 | Parameters 133 | ---------- 134 | param lat1: float, latitude of the first point 135 | param lon1: float, longitude of the first point 136 | param lat2: float, latitude of the second point 137 | param lon2: float, longitude of the second point 138 | param lat3: float, latitude of the third point 139 | param lon3: float, longitude of the third point 140 | 141 | Returns 142 | ------- 143 | 144 | ptp : float 145 | The point-to-path distance between point (lon3, lat3) and path delimited by (lon1, lat1) and (lon2, lat2) 146 | 147 | """ 148 | crt = cross_track_distance(lon1, lat1, lon2, lat2, lon3, lat3) 149 | d1p = along_track_distance(crt, lon1, lat1, lon3, lat3) 150 | d2p = along_track_distance(crt, lon2, lat2, lon3, lat3) 151 | d12 = great_circle_distance(lon1, lat1, lon2, lat2) 152 | if (d1p > d12) or (d2p > d12): 153 | ptp = np.min((great_circle_distance(lon1, lat1, lon3, lat3), great_circle_distance(lon2, lat2, lon3, lat3))) 154 | else: 155 | ptp = np.abs(crt) 156 | return ptp -------------------------------------------------------------------------------- /traj_dist/pydist/basic_geographical.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/pydist/basic_geographical.pyc -------------------------------------------------------------------------------- /traj_dist/pydist/discret_frechet.py: -------------------------------------------------------------------------------- 1 | ## https://www.snip2code.com/Snippet/76076/Fr-chet-Distance-in-Python 2 | ## Computing Discrete Frechet Distance 3 | ## Thomas Eiter and Heikki Mannila 4 | ## Christian Dopler Labor fur Expertensyteme. Technische Universitat Wien 5 | 6 | from basic_euclidean import eucl_dist 7 | import numpy as np 8 | 9 | def _c(ca,i,j,P,Q): 10 | if ca[i,j] > -1: 11 | return ca[i,j] 12 | elif i == 0 and j == 0: 13 | ca[i,j] = eucl_dist(P[0],Q[0]) 14 | elif i > 0 and j == 0: 15 | ca[i,j] = max(_c(ca,i-1,0,P,Q),eucl_dist(P[i],Q[0])) 16 | elif i == 0 and j > 0: 17 | ca[i,j] = max(_c(ca,0,j-1,P,Q),eucl_dist(P[0],Q[j])) 18 | elif i > 0 and j > 0: 19 | ca[i,j] = max(min(_c(ca,i-1,j,P,Q),_c(ca,i-1,j-1,P,Q),_c(ca,i,j-1,P,Q)),eucl_dist(P[i],Q[j])) 20 | else: 21 | ca[i,j] = float("inf") 22 | return ca[i,j] 23 | 24 | 25 | def discret_frechet(P,Q): 26 | """ 27 | Usage 28 | ----- 29 | Compute the discret frechet distance between trajectories P and Q 30 | 31 | Parameters 32 | ---------- 33 | param P : px2 numpy_array, Trajectory P 34 | param Q : qx2 numpy_array, Trajectory Q 35 | 36 | Returns 37 | ------- 38 | frech : float, the discret frechet distance between trajectories P and Q 39 | """ 40 | ca = np.ones((len(P),len(Q))) 41 | ca = np.multiply(ca,-1) 42 | return _c(ca,len(P)-1,len(Q)-1,P,Q) 43 | -------------------------------------------------------------------------------- /traj_dist/pydist/discret_frechet.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/pydist/discret_frechet.pyc -------------------------------------------------------------------------------- /traj_dist/pydist/dtw.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from basic_euclidean import eucl_dist 3 | from basic_geographical import great_circle_distance 4 | 5 | ############# 6 | # euclidean # 7 | ############# 8 | 9 | def e_dtw(t0,t1): 10 | """ 11 | Usage 12 | ----- 13 | The Dynamic-Time Warping distance between trajectory t0 and t1. 14 | 15 | Parameters 16 | ---------- 17 | param t0 : len(t0)x2 numpy_array 18 | param t1 : len(t1)x2 numpy_array 19 | 20 | Returns 21 | ------- 22 | dtw : float 23 | The Dynamic-Time Warping distance between trajectory t0 and t1 24 | """ 25 | 26 | n0 = len(t0) 27 | n1 = len(t1) 28 | C=np.zeros((n0+1,n1+1)) 29 | C[1:,0]=float('inf') 30 | C[0,1:]=float('inf') 31 | for i in np.arange(n0)+1: 32 | for j in np.arange(n1)+1: 33 | C[i,j]=eucl_dist(t0[i-1],t1[j-1]) + min(C[i,j-1],C[i-1,j-1],C[i-1,j]) 34 | dtw = C[n0,n1] 35 | return dtw 36 | 37 | ################ 38 | # geographical # 39 | ################ 40 | 41 | def g_dtw(t0,t1): 42 | """ 43 | Usage 44 | ----- 45 | The Dynamic-Time Warping distance between trajectory t0 and t1. 46 | 47 | Parameters 48 | ---------- 49 | param t0 : len(t0)x2 numpy_array 50 | param t1 : len(t1)x2 numpy_array 51 | 52 | Returns 53 | ------- 54 | dtw : float 55 | The Dynamic-Time Warping distance between trajectory t0 and t1 56 | """ 57 | n0 = len(t0) 58 | n1 = len(t1) 59 | C=np.zeros((n0+1,n1+1)) 60 | C[1:,0]=float('inf') 61 | C[0,1:]=float('inf') 62 | for i in np.arange(n0)+1: 63 | for j in np.arange(n1)+1: 64 | C[i,j]=great_circle_distance(t0[i-1][0],t0[i-1][1],t1[j-1][0],t1[j-1][1]) + min(C[i,j-1],C[i-1,j-1],C[i-1,j]) 65 | dtw = C[n0,n1] 66 | return dtw -------------------------------------------------------------------------------- /traj_dist/pydist/dtw.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/pydist/dtw.pyc -------------------------------------------------------------------------------- /traj_dist/pydist/edr.py: -------------------------------------------------------------------------------- 1 | from basic_euclidean import eucl_dist 2 | from basic_geographical import great_circle_distance 3 | 4 | ############# 5 | # euclidean # 6 | ############# 7 | 8 | def e_edr(t0, t1,eps): 9 | """ 10 | Usage 11 | ----- 12 | The Edit Distance on Real sequence between trajectory t0 and t1. 13 | 14 | Parameters 15 | ---------- 16 | param t0 : len(t0)x2 numpy_array 17 | param t1 : len(t1)x2 numpy_array 18 | eps : float 19 | 20 | Returns 21 | ------- 22 | edr : float 23 | The Longuest-Common-Subsequence distance between trajectory t0 and t1 24 | """ 25 | n0 = len(t0) 26 | n1 = len(t1) 27 | # An (m+1) times (n+1) matrix 28 | C = [[0] * (n1+1) for _ in range(n0+1)] 29 | for i in range(1, n0+1): 30 | for j in range(1, n1+1): 31 | if eucl_dist(t0[i-1],t1[j-1]) eps: 38 | lf = [-1, -1] 39 | else: 40 | lf = [0, 1] 41 | else: 42 | if point_to_seg(p, s[0], s[1]) > eps: 43 | #print("No Intersection") 44 | lf = [-1, -1] 45 | else: 46 | segl = eucl_dist(s[0], s[1]) 47 | segl2 = segl * segl 48 | intersect = circle_line_intersection(px, py, s1x, s1y, s2x, s2y, eps) 49 | if intersect[0][0] != intersect[1][0] or intersect[0][1] != intersect[1][1]: 50 | i1x = intersect[0, 0] 51 | i1y = intersect[0, 1] 52 | u1 = (((i1x - s1x) * (s2x - s1x)) + ((i1y - s1y) * (s2y - s1y))) / segl2 53 | 54 | i2x = intersect[1, 0] 55 | i2y = intersect[1, 1] 56 | u2 = (((i2x - s1x) * (s2x - s1x)) + ((i2y - s1y) * (s2y - s1y))) / segl2 57 | ordered_point = sorted((0, 1, u1, u2)) 58 | lf = ordered_point[1:3] 59 | else: 60 | if px == s1x and py==s1y: 61 | lf = [0, 0] 62 | elif px == s2x and py==s2y: 63 | lf = [1, 1] 64 | else: 65 | i1x = intersect[0][0] 66 | i1y = intersect[0][1] 67 | u1 = (((i1x - s1x) * (s2x - s1x)) + ((i1y - s1y) * (s2y - s1y))) / segl2 68 | if 0 <= u1 <= 1: 69 | lf = [u1, u1] 70 | else: 71 | lf = [-1, -1] 72 | return lf 73 | 74 | 75 | def LF_BF(P, Q, p, q, eps): 76 | """ 77 | Usage 78 | ----- 79 | Compute all the free space on the boundary of cells in the diagram for polygonal chains P and Q and the given eps 80 | LF[(i,j)] is the free space of segment [Pi,Pi+1] from point Qj 81 | BF[(i,j)] is the free space of segment [Qj,Qj+1] from point Pj 82 | 83 | Parameters 84 | ---------- 85 | param P : px2 numpy_array, Trajectory P 86 | param Q : qx2 numpy_array, Trajectory Q 87 | param p : float, number of points in Trajectory P 88 | param q : float, number of points in Trajectory Q 89 | param eps : float, reachability distance 90 | 91 | Returns 92 | ------- 93 | LF : dict, free spaces of segments of P from points of Q 94 | BF : dict, free spaces of segments of Q from points of P 95 | """ 96 | LF = {} 97 | for j in range(q): 98 | for i in range(p - 1): 99 | LF.update({(i, j): free_line(Q[j], eps, P[i:i + 2])}) 100 | BF = {} 101 | for j in range(q - 1): 102 | for i in range(p): 103 | BF.update({(i, j): free_line(P[i], eps, Q[j:j + 2])}) 104 | return LF, BF 105 | 106 | 107 | def LR_BR(LF, BF, p, q): 108 | """ 109 | Usage 110 | ----- 111 | Compute all the free space,that are reachable from the origin (P[0,0],Q[0,0]) on the boundary of cells 112 | in the diagram for polygonal chains P and Q and the given free spaces LR and BR 113 | 114 | LR[(i,j)] is the free space, reachable from the origin, of segment [Pi,Pi+1] from point Qj 115 | BR[(i,j)] is the free space, reachable from the origin, of segment [Qj,Qj+1] from point Pj 116 | 117 | Parameters 118 | ---------- 119 | LF : dict, free spaces of segments of P from points of Q 120 | BF : dict, free spaces of segments of Q from points of P 121 | param p : float, number of points in Trajectory P 122 | param q : float, number of points in Trajectory Q 123 | 124 | Returns 125 | ------- 126 | rep : bool, return true if frechet distance is inf to eps 127 | LR : dict, is the free space, reachable from the origin, of segments of P from points of Q 128 | BR : dict, is the free space, reachable from the origin, of segments of Q from points of P 129 | """ 130 | if not (LF[(0, 0)][0] <= 0 and BF[(0, 0)][0] <= 0 and LF[(p - 2, q - 1)][1] >= 1 and BF[(p - 1, q - 2)][1] >= 1 ): 131 | rep = False 132 | BR={} 133 | LR={} 134 | else: 135 | LR = {(0, 0): True} 136 | BR = {(0, 0): True} 137 | for i in range(1, p - 1): 138 | if LF[(i, 0)] != [-1, -1] and LF[(i - 1, 0)] == [0, 1]: 139 | LR[(i, 0)] = True 140 | else: 141 | LR[(i, 0)] = False 142 | for j in range(1, q - 1): 143 | if BF[(0, j)] != [-1, -1] and BF[(0, j - 1)] == [0, 1]: 144 | BR[(0, j)] = True 145 | else: 146 | BR[(0, j)] = False 147 | for i in range(p - 1): 148 | for j in range(q - 1): 149 | if LR[(i, j)] or BR[(i, j)]: 150 | if LF[(i, j + 1)] != [-1, -1]: 151 | LR[(i, j + 1)] = True 152 | else: 153 | LR[(i, j + 1)] = False 154 | if BF[(i + 1, j)] != [-1, -1]: 155 | BR[(i + 1, j)] = True 156 | else: 157 | BR[(i + 1, j)] = False 158 | else: 159 | LR[(i, j + 1)] = False 160 | BR[(i + 1, j)] = False 161 | rep = BR[(p - 2, q - 2)] or LR[(p - 2, q - 2)] 162 | return rep, LR, BR 163 | 164 | 165 | def decision_problem(P, Q, p, q, eps): 166 | """ 167 | Usage 168 | ----- 169 | Test is the frechet distance between trajectories P and Q are inferior to eps 170 | 171 | Parameters 172 | ---------- 173 | param P : px2 numpy_array, Trajectory P 174 | param Q : qx2 numpy_array, Trajectory Q 175 | param p : float, number of points in Trajectory P 176 | param q : float, number of points in Trajectory Q 177 | param eps : float, reachability distance 178 | 179 | Returns 180 | ------- 181 | rep : bool, return true if frechet distance is inf to eps 182 | """ 183 | LF, BF = LF_BF(P, Q, p, q, eps) 184 | rep, _, _ = LR_BR(LF, BF, p, q) 185 | return rep 186 | 187 | 188 | def compute_critical_values(P, Q, p, q): 189 | """ 190 | Usage 191 | ----- 192 | Compute all the critical values between trajectories P and Q 193 | 194 | Parameters 195 | ---------- 196 | param P : px2 numpy_array, Trajectory P 197 | param Q : qx2 numpy_array, Trajectory Q 198 | param p : float, number of points in Trajectory P 199 | param q : float, number of points in Trajectory Q 200 | 201 | Returns 202 | ------- 203 | cc : list, all critical values between trajectories P and Q 204 | """ 205 | origin = eucl_dist(P[0], Q[0]) 206 | end = eucl_dist(P[-1], Q[-1]) 207 | end_point = max(origin, end) 208 | cc = set([end_point]) 209 | for i in range(p - 1): 210 | for j in range(q - 1): 211 | Lij = point_to_seg(Q[j], P[i], P[i + 1]) 212 | if Lij > end_point: 213 | cc.add(Lij) 214 | Bij = point_to_seg(P[i], Q[j], Q[j + 1]) 215 | if Bij > end_point: 216 | cc.add(Bij) 217 | return sorted(list(cc)) 218 | 219 | 220 | def frechet(P, Q): 221 | """ 222 | Usage 223 | ----- 224 | Compute the frechet distance between trajectories P and Q 225 | 226 | Parameters 227 | ---------- 228 | param P : px2 numpy_array, Trajectory P 229 | param Q : qx2 numpy_array, Trajectory Q 230 | 231 | Returns 232 | ------- 233 | frech : float, the frechet distance between trajectories P and Q 234 | """ 235 | p = len(P) 236 | q = len(Q) 237 | 238 | cc = compute_critical_values(P, Q, p, q) 239 | eps=cc[0] 240 | while (len(cc) != 1): 241 | m_i = len(cc) / 2 - 1 242 | eps = cc[m_i] 243 | rep = decision_problem(P, Q, p, q, eps) 244 | if rep: 245 | cc = cc[:m_i + 1] 246 | else: 247 | cc = cc[m_i + 1:] 248 | frech = eps 249 | return frech 250 | -------------------------------------------------------------------------------- /traj_dist/pydist/frechet.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/pydist/frechet.pyc -------------------------------------------------------------------------------- /traj_dist/pydist/hausdorff.py: -------------------------------------------------------------------------------- 1 | from basic_euclidean import point_to_trajectory 2 | from basic_geographical import point_to_path 3 | 4 | ############# 5 | # euclidean # 6 | ############# 7 | 8 | def e_directed_hausdorff (t1, t2): 9 | """ 10 | Usage 11 | ----- 12 | directed hausdorff distance from trajectory t1 to trajectory t2. 13 | 14 | Parameters 15 | ---------- 16 | param t1 : len(t1)x2 numpy_array 17 | param t2 : len(t2)x2 numpy_array 18 | 19 | Returns 20 | ------- 21 | dh : float, directed hausdorff from trajectory t1 to trajectory t2 22 | """ 23 | dh=max(map(lambda p : point_to_trajectory(p,t2),t1)) 24 | return dh 25 | 26 | 27 | def e_hausdorff(t1,t2): 28 | """ 29 | Usage 30 | ----- 31 | hausdorff distance between trajectories t1 and t2. 32 | 33 | Parameters 34 | ---------- 35 | param t1 : len(t1)x2 numpy_array 36 | param t2 : len(t2)x2 numpy_array 37 | 38 | Returns 39 | ------- 40 | h : float, hausdorff from trajectories t1 and t2 41 | """ 42 | h=max(e_directed_hausdorff(t1,t2), e_directed_hausdorff(t2,t1)) 43 | return h 44 | 45 | ################ 46 | # geographical # 47 | ################ 48 | 49 | def g_directed_hausdorff (t1, t2): 50 | """ 51 | Usage 52 | ----- 53 | directed hausdorff distance from trajectory t1 to trajectory t2. 54 | 55 | Parameters 56 | ---------- 57 | param t1 : len(t1)x2 numpy_array 58 | param t2 : len(t2)x2 numpy_array 59 | 60 | Returns 61 | ------- 62 | dh : float, directed hausdorff from trajectory t1 to trajectory t2 63 | """ 64 | n0=len(t1) 65 | n1=len(t2) 66 | dh=0 67 | for j in range(n1) : 68 | dist_j0=9e100 69 | for i in range(n0-1): 70 | dist_j0=min(dist_j0,point_to_path(t1[i][0],t1[i][1],t1[i+1][0],t1[i+1][1],t2[j][0],t2[j][1])) 71 | dh=max(dh,dist_j0) 72 | return dh 73 | 74 | 75 | def g_hausdorff(t1,t2): 76 | """ 77 | Usage 78 | ----- 79 | hausdorff distance between trajectories t1 and t2. 80 | 81 | Parameters 82 | ---------- 83 | param t1 : len(t1)x2 numpy_array 84 | param t2 : len(t2)x2 numpy_array 85 | 86 | Returns 87 | ------- 88 | h : float, hausdorff from trajectories t1 and t2 89 | """ 90 | h=max(g_directed_hausdorff(t1,t2), g_directed_hausdorff(t2,t1)) 91 | return h 92 | 93 | -------------------------------------------------------------------------------- /traj_dist/pydist/hausdorff.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/pydist/hausdorff.pyc -------------------------------------------------------------------------------- /traj_dist/pydist/lcss.py: -------------------------------------------------------------------------------- 1 | from basic_euclidean import eucl_dist 2 | from basic_geographical import great_circle_distance 3 | 4 | ############# 5 | # euclidean # 6 | ############# 7 | 8 | def e_lcss(t0, t1,eps): 9 | """ 10 | Usage 11 | ----- 12 | The Longuest-Common-Subsequence distance between trajectory t0 and t1. 13 | 14 | Parameters 15 | ---------- 16 | param t0 : len(t0)x2 numpy_array 17 | param t1 : len(t1)x2 numpy_array 18 | eps : float 19 | 20 | Returns 21 | ------- 22 | lcss : float 23 | The Longuest-Common-Subsequence distance between trajectory t0 and t1 24 | """ 25 | n0 = len(t0) 26 | n1 = len(t1) 27 | # An (m+1) times (n+1) matrix 28 | C = [[0] * (n1+1) for _ in range(n0+1)] 29 | for i in range(1, n0+1): 30 | for j in range(1, n1+1): 31 | if eucl_dist(t0[i-1],t1[j-1]) p2[1])[0][0] 15 | lats = lats_all[lats_start_index:lats_end_index + 1] 16 | 17 | if p1[0] < p2[0]: 18 | order = "croissant" 19 | idx_step = 1 20 | lons_start_index = np.where(lons_all < p1[0])[0][-1] 21 | lons_end_index = np.where(lons_all > p2[0])[0][0] 22 | lons = lons_all[lons_start_index:lons_end_index + 1] 23 | else: 24 | order = "decroissant" 25 | idx_step = -1 26 | lons_start_index = np.where(lons_all < p2[0])[0][-1] 27 | lons_end_index = np.where(lons_all > p1[0])[0][0] 28 | lons = lons_all[lons_start_index:lons_end_index + 1] 29 | lons = lons[::-1] 30 | line = geos.LineString([p1, p2]) 31 | 32 | nlons = len(lons) - 2 33 | nlats = len(lats) - 2 34 | 35 | if not (reverse): 36 | cell = [cell_start] 37 | else: 38 | if order == "croissant": 39 | cell = [[cell_start[0] - nlons, cell_start[1] - nlats]] 40 | else: 41 | cell = [[cell_start[0] + nlons, cell_start[1] - nlats]] 42 | 43 | lons_inter = [] 44 | for l in lons[1:-1]: 45 | lons_shape = geos.LineString([[l, lats[0]], [l, lats[-1]]]) 46 | lons_inter.append(lons_shape.intersection(line)) 47 | 48 | idx_lat = 0 49 | for p_int in lons_inter: 50 | if p_int.y < lats[idx_lat + 1]: 51 | cell.append([cell[-1][0] + idx_step, cell[-1][1]]) 52 | else: 53 | cell.append([cell[-1][0], cell[-1][1] + 1]) 54 | cell.append([cell[-1][0] + idx_step, cell[-1][1]]) 55 | idx_lat += 1 56 | if p2[1] > lats[idx_lat + 1]: 57 | cell.append([cell[-1][0], cell[-1][1] + 1]) 58 | if reverse: 59 | cell.reverse() 60 | cells_coord = map(lambda x: [lons_center_all[x[0]], lats_center_all[x[1]]], cell) 61 | return cell, cells_coord 62 | 63 | 64 | def linecell_lats_bigger_step(p1, p2, cell_start, lons_all, lats_all, lons_center_all, lats_center_all): 65 | reverse = False 66 | if p2[0] < p1[0]: 67 | tmp = p1 68 | p1 = p2 69 | p2 = tmp 70 | reverse = True 71 | 72 | lons_start_index = np.where(lons_all < p1[0])[0][-1] 73 | lons_end_index = np.where(lons_all > p2[0])[0][0] 74 | lons = lons_all[lons_start_index:lons_end_index + 1] 75 | 76 | if p1[1] < p2[1]: 77 | order = "croissant" 78 | idx_step = 1 79 | lats_start_index = np.where(lats_all < p1[1])[0][-1] 80 | lats_end_index = np.where(lats_all > p2[1])[0][0] 81 | lats = lats_all[lats_start_index:lats_end_index + 1] 82 | else: 83 | order = "decroissant" 84 | idx_step = -1 85 | lats_start_index = np.where(lats_all < p2[1])[0][-1] 86 | lats_end_index = np.where(lats_all > p1[1])[0][0] 87 | lats = lats_all[lats_start_index:lats_end_index + 1] 88 | lats = lats[::-1] 89 | line = geos.LineString([p1, p2]) 90 | 91 | nlons = len(lons) - 2 92 | nlats = len(lats) - 2 93 | 94 | if not (reverse): 95 | cell = [cell_start] 96 | else: 97 | if order == "croissant": 98 | cell = [[cell_start[0] - nlons, cell_start[1] - nlats]] 99 | else: 100 | cell = [[cell_start[0] - nlons, cell_start[1] + nlats]] 101 | 102 | lats_inter = [] 103 | for l in lats[1:-1]: 104 | lats_shape = geos.LineString([[lons[0], l], [lons[-1], l]]) 105 | lats_inter.append(lats_shape.intersection(line)) 106 | 107 | idx_lon = 0 108 | for p_int in lats_inter: 109 | if p_int.x < lons[idx_lon + 1]: 110 | cell.append([cell[-1][0], cell[-1][1] + idx_step]) 111 | else: 112 | cell.append([cell[-1][0] + 1, cell[-1][1]]) 113 | cell.append([cell[-1][0], cell[-1][1] + idx_step]) 114 | idx_lon += 1 115 | if p2[0] > lons[idx_lon + 1]: 116 | cell.append([cell[-1][0] + 1, cell[-1][1]]) 117 | if reverse: 118 | cell.reverse() 119 | cells_coord = map(lambda x: [lons_center_all[x[0]], lats_center_all[x[1]]], cell) 120 | return cell, cells_coord 121 | 122 | 123 | def get_extremum(traj): 124 | lons = traj[:, 0] 125 | lats = traj[:, 1] 126 | min_lon = min(lons) 127 | min_lat = min(lats) 128 | max_lon = max(lons) 129 | max_lat = max(lats) 130 | return min_lon, min_lat, max_lon, max_lat 131 | 132 | 133 | def trajectory_set_grid(traj_set, precision, time=False): 134 | extremums = np.array(map(get_extremum, traj_set)) 135 | p_bottom_left = [min(extremums[:, 0]), min(extremums[:, 1])] 136 | p_top_right = [max(extremums[:, 2]), max(extremums[:, 3])] 137 | p_ble = geoh.encode(p_bottom_left[1], p_bottom_left[0], precision) 138 | p_tre = geoh.encode(p_top_right[1], p_top_right[0], precision) 139 | lat_ble, lon_ble, dlat, dlon = geoh.decode_exactly(p_ble) 140 | lat_tre, lon_tre, dlat, dlon = geoh.decode_exactly(p_tre) 141 | lats_all = np.arange(lat_ble - dlat, lat_tre + (3 * dlat), dlat * 2) 142 | lons_all = np.arange(lon_ble - dlon, lon_tre + 3 * dlon, dlon * 2) 143 | lats_center_all = np.arange(lat_ble, lat_tre + 2 * dlat, dlat * 2) 144 | lons_center_all = np.arange(lon_ble, lon_tre + 2 * dlon, dlon * 2) 145 | 146 | cells_traj = [] 147 | for traj in traj_set: 148 | p_start = traj[0] 149 | cell_start_x = np.where(lons_all < p_start[0])[0][-1] 150 | cell_start_y = np.where(lats_all < p_start[1])[0][-1] 151 | cell_start = [cell_start_x, cell_start_y] 152 | 153 | cells = [] 154 | 155 | for id_seg in range(len(traj) - 1): 156 | start = traj[id_seg] 157 | end = traj[id_seg + 1] 158 | if time: 159 | cell_start_time = start[2] 160 | if abs(start[0] - end[0]) / dlon > abs(start[1] - end[1]) / dlat: 161 | cell, cells_coord = linecell_lons_bigger_step(start, end, cell_start[:2], lons_all, lats_all, 162 | lons_center_all, 163 | lats_center_all) 164 | else: 165 | cell, cells_coord = linecell_lats_bigger_step(start, end, cell_start[:2], lons_all, lats_all, 166 | lons_center_all, 167 | lats_center_all) 168 | if time: 169 | if not cells: 170 | cell_time = [cell[0] + [True, [cell_start_time]]] 171 | else: 172 | if cell[0] == cells[-1][:2]: 173 | cells[-1][3].append(cell_start_time) 174 | cell_time = [] 175 | else: 176 | cell_time = [cell[0] + [True, [cell_start_time]]] 177 | cell_time = cell_time + map(lambda x: x + [False, -1], cell[1:-1]) 178 | else: 179 | if not cells: 180 | cell_time = [cell[0] + [True]] 181 | else: 182 | if cell[0] == cells[-1][:2]: 183 | cell_time = [] 184 | else: 185 | cell_time = [cell[0] + [True]] 186 | cell_time = cell_time + map(lambda x: x + [False], cell[1:-1]) 187 | 188 | cells.extend(cell_time) 189 | cell_start = cell[-1] 190 | if time: 191 | cell_end_time = end[2] 192 | if cell_start == cells[-1][:2]: 193 | cells[-1][3].append(cell_end_time) 194 | else: 195 | cells.append(cell_start + [True, [cell_end_time]]) 196 | else: 197 | if cell_start != cells[-1][:2]: 198 | cells.append(cell_start + [True]) 199 | cells_traj.append(cells) 200 | # cells_traj_=map(np.array,cells_traj) 201 | return cells_traj, lons_all, lats_all, lons_center_all, lats_center_all 202 | 203 | 204 | def trajectory_grid(traj_0, precision): 205 | cells_list, lons_all, lats_all, lons_center_all, lats_center_all = trajectory_set_grid([traj_0], precision) 206 | return cells_list[0], lons_all, lats_all, lons_center_all, lats_center_all 207 | 208 | -------------------------------------------------------------------------------- /traj_dist/pydist/linecell.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/pydist/linecell.pyc -------------------------------------------------------------------------------- /traj_dist/pydist/segment_distance.py: -------------------------------------------------------------------------------- 1 | from basic_euclidean import eucl_dist 2 | import math 3 | import numpy as np 4 | PI=math.pi 5 | HPI=math.pi/2 6 | 7 | 8 | def ordered_mixed_distance(si,ei,sj,ej,siei,sjej,siei_norm_2,sjej_norm_2): 9 | 10 | siei_norm=math.sqrt(siei_norm_2) 11 | sjej_norm=math.sqrt(sjej_norm_2) 12 | sisj=sj-si 13 | siej=ej-si 14 | 15 | u1=(sisj[0]*siei[0]+sisj[1]*siei[1])/siei_norm_2 16 | u2=(siej[0]*siei[0]+siej[1]*siei[1])/siei_norm_2 17 | 18 | ps=si+u1*siei 19 | pe=si+u2*siei 20 | 21 | cos_theta = max(-1,min(1,(sjej[0]*siei[0]+sjej[1]*siei[1])/(siei_norm*sjej_norm))) 22 | theta = math.acos(cos_theta) 23 | 24 | #perpendicular distance 25 | lpe1=eucl_dist(sj,ps) 26 | lpe2=eucl_dist(ej,pe) 27 | if lpe1==0 and lpe2==0: 28 | dped= 0 29 | else: 30 | dped = (lpe1*lpe1+lpe2*lpe2)/(lpe1+lpe2) 31 | 32 | #parallel_distance 33 | lpa1=min(eucl_dist(si,ps),eucl_dist(ei,ps)) 34 | lpa2=min(eucl_dist(si,pe),eucl_dist(ei,pe)) 35 | dpad=min(lpa1,lpa2) 36 | 37 | #angle_distance 38 | if 0 <= theta siei_norm_2 : 57 | md=ordered_mixed_distance(sj,ej,si,ei,sjej,siei,sjej_norm_2,siei_norm_2) 58 | else : 59 | md=ordered_mixed_distance(si,ei,sj,ej,siei,sjej,siei_norm_2,sjej_norm_2) 60 | 61 | return md 62 | 63 | def segments_distance(traj_0,traj_1): 64 | 65 | n0=len(traj_0) 66 | n1=len(traj_1) 67 | M=np.zeros((n0-1,n1-1)) 68 | for i in range(n0-1): 69 | for j in range(n1-1): 70 | M[i,j]=mixed_distance(traj_0[i],traj_0[i+1],traj_1[j],traj_1[j+1]) 71 | return M 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /traj_dist/pydist/sowd.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import linecell as linec 3 | 4 | 5 | def owd_grid_brut(traj_cell_1,traj_cell_2): 6 | """ 7 | Usage 8 | ----- 9 | The owd-distance of trajectory t2 from trajectory t1 10 | 11 | Parameters 12 | ---------- 13 | param traj_cell_1 : len(t1)x2 numpy_array 14 | param traj_cell_2 : len(t2)x2 numpy_array 15 | 16 | Returns 17 | ------- 18 | owd : float 19 | owd-distance of trajectory t2 from trajectory t1 20 | """ 21 | D=0 22 | n=len(traj_cell_1) 23 | for p1 in traj_cell_1: 24 | d=map(lambda x : np.linalg.norm(p1-x),traj_cell_2) 25 | D+=min(d) 26 | owd = D/n 27 | return D/n 28 | 29 | 30 | def find_first_min_points(pt, n): 31 | """ 32 | Usage 33 | ----- 34 | Return the index of the min-point in the vector pt of size n. 35 | 36 | Parameters 37 | ---------- 38 | param pt : len(t1)x1 numpy_array 39 | param n : int 40 | 41 | Returns 42 | ------- 43 | min_point_index : nbumber of min points x1 numpy_array 44 | 45 | """ 46 | if n == 1: 47 | min_points = [True] 48 | else: 49 | min_points = [pt[0] < pt[1]] 50 | for i in range(1, n - 1): 51 | m_p = pt[i] < pt[i + 1] and pt[i] < pt[i - 1] 52 | min_points.append(m_p) 53 | min_points.append(pt[n - 1] < pt[n - 2]) 54 | min_point_index = np.where(np.array(min_points))[0] 55 | return min_point_index 56 | 57 | def owd_grid(traj_cell_1,traj_cell_2): 58 | """ 59 | Usage 60 | ----- 61 | The owd-distance of trajectory t2 from trajectory t1 62 | 63 | Parameters 64 | ---------- 65 | param traj_cell_1 : len(t1)x2 numpy_array 66 | param traj_cell_2 : len(t2)x2 numpy_array 67 | 68 | Returns 69 | ------- 70 | owd : float 71 | owd-distance of trajectory t2 from trajectory t1 72 | """ 73 | n1 = len(traj_cell_1) 74 | n2 = len(traj_cell_2) 75 | 76 | p = traj_cell_1[0] 77 | p_t2 = map(lambda x: np.linalg.norm(p - x), traj_cell_2) 78 | S_old = find_first_min_points(p_t2, n2) 79 | D = min(p_t2) 80 | for i in range(1, n1): 81 | p_prec = p 82 | p = traj_cell_1[i] 83 | S = [] 84 | d = [] 85 | n_S_old=len(S_old) 86 | for j in range(n_S_old): 87 | ig = S_old[j] 88 | pg = traj_cell_2[ig] 89 | if (p_prec[1] == p[1]) and (pg[0] != p_prec[0]) or (p_prec[0] == p[0]) and (pg[1] != p_prec[1]): 90 | S.append(ig) 91 | d.append(np.linalg.norm(p - pg)) 92 | else: 93 | if j == 0: 94 | if n_S_old == 1 : 95 | ranges = range(0,n2) 96 | else: 97 | ranges = range(0, S_old[j + 1]) 98 | elif j == n_S_old - 1: 99 | ranges = range(S_old[j - 1], n2) 100 | else: 101 | ranges = range(S_old[j - 1] + 1, S_old[j + 1]) 102 | for igp in ranges: 103 | pgp = traj_cell_2[igp] 104 | if (p_prec[1] == p[1] and pgp[0] == p[0]) or (p_prec[0] == p[0] and pgp[1] == p[1]) or igp==ig : 105 | dist_back = np.linalg.norm(traj_cell_2[igp - 1]-p) if igp!=0 else np.inf 106 | dist_forw = np.linalg.norm(traj_cell_2[igp + 1]-p) if igp!= n2-1 else np.inf 107 | dist = np.linalg.norm(pgp - p) 108 | if dist < dist_back and dist < dist_forw: 109 | if not (igp in S): 110 | S.append(igp) 111 | d.append(dist) 112 | S_old=S 113 | #p_t2 = map(lambda x: np.linalg.norm(traj_cell_1[i] - x), traj_cell_2) 114 | #print(np.all(map(lambda x,y:x==y,S_old,find_first_min_points(p_t2, n2)))) 115 | D += min(d) 116 | return D/n1 117 | 118 | 119 | def sowd_grid(traj_cell_1,traj_cell_2): 120 | sowd_dist=owd_grid(traj_cell_1,traj_cell_2)+owd_grid(traj_cell_2,traj_cell_1) 121 | return sowd_dist/2 122 | 123 | def sowd_grid_brut(traj_cell_1,traj_cell_2): 124 | sowd_brut_dist = owd_grid_brut(traj_cell_1,traj_cell_2)+owd_grid_brut(traj_cell_2,traj_cell_1) 125 | return sowd_brut_dist/2 126 | 127 | def sowd(traj_1,traj_2,precision=7,converted=False): 128 | if converted: 129 | d = sowd_grid(traj_1,traj_2) 130 | else: 131 | cells_list, _, _ = linec.trajectory_set_grid([traj_1,traj_2], precision) 132 | d = sowd_grid(cells_list[0],cells_list[1]) 133 | return d 134 | 135 | def sowd_brut(traj_1,traj_2,precision=7,converted=False): 136 | if converted: 137 | d = sowd_grid_brut(traj_1,traj_2) 138 | else: 139 | cells_list, _, _ = linec.trajectory_set_grid([traj_1,traj_2], precision) 140 | d = sowd_grid_brut(cells_list[0],cells_list[1]) 141 | return d 142 | -------------------------------------------------------------------------------- /traj_dist/pydist/sowd.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/pydist/sowd.pyc -------------------------------------------------------------------------------- /traj_dist/pydist/sspd.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from basic_euclidean import point_to_trajectory 3 | from basic_geographical import point_to_path 4 | ############### 5 | ## euclidean ## 6 | ############### 7 | 8 | def e_spd (t1, t2): 9 | """ 10 | Usage 11 | ----- 12 | The spd-distance of trajectory t2 from trajectory t1 13 | The spd-distance is the sum of the all the point-to-trajectory distance of points of t1 from trajectory t2 14 | 15 | Parameters 16 | ---------- 17 | param t1 : len(t1)x2 numpy_array 18 | param t2 : len(t2)x2 numpy_array 19 | 20 | Returns 21 | ------- 22 | spd : float 23 | spd-distance of trajectory t2 from trajectory t1 24 | """ 25 | spd=sum(map(lambda p : point_to_trajectory(p,t2),t1))/len(t1) 26 | return spd 27 | 28 | def e_sspd (t1, t2): 29 | """ 30 | Usage 31 | ----- 32 | The sspd-distance between trajectories t1 and t2. 33 | The sspd-distance is the mean of the spd-distance between of t1 from t2 and the spd-distance of t2 from t1. 34 | 35 | Parameters 36 | ---------- 37 | param t1 : len(t1)x2 numpy_array 38 | param t2 : len(t2)x2 numpy_array 39 | 40 | Returns 41 | ------- 42 | sspd : float 43 | sspd-distance of trajectory t2 from trajectory t1 44 | """ 45 | sspd=(e_spd(t1,t2) + e_spd(t2,t1))/2 46 | return sspd 47 | 48 | ################# 49 | ## geographical## 50 | ################# 51 | 52 | def g_spd(t1, t2): 53 | """ 54 | Usage 55 | ----- 56 | The spd-distance of trajectory t2 from trajectory t1 57 | The spd-distance is the sum of the all the point-to-path distance of points of t1 from trajectory t2 58 | 59 | Parameters 60 | ---------- 61 | param t1 : len(t1)x2 numpy_array 62 | param t2 : len(t2)x2 numpy_array 63 | 64 | Returns 65 | ------- 66 | spd : float 67 | spd-distance of trajectory t2 from trajectory t1 68 | """ 69 | n0 = len(t1) 70 | n1 = len(t2) 71 | lats0 = t1[:, 1] 72 | lons0 = t1[:, 0] 73 | lats1 = t2[:, 1] 74 | lons1 = t2[:, 0] 75 | dist = 0 76 | for j in range(n1): 77 | dist_j0 = 9e100 78 | for i in range(n0 - 1): 79 | dist_j0 = np.min((dist_j0, point_to_path(lons0[i], lats0[i], lons0[i + 1], lats0[i + 1], lons1[j], 80 | lats1[j]))) 81 | dist = dist + dist_j0 82 | dist = float(dist) / n1 83 | return dist 84 | 85 | 86 | def g_sspd(t1, t2): 87 | """ 88 | Usage 89 | ----- 90 | The sspd-distance between trajectories t1 and t2. 91 | The sspd-distance is the mean of the spd-distance between of t1 from t2 and the spd-distance of t2 from t1. 92 | 93 | Parameters 94 | ---------- 95 | param t1 : len(t1)x2 numpy_array 96 | param t2 : len(t2)x2 numpy_array 97 | 98 | Returns 99 | ------- 100 | sspd : float 101 | sspd-distance of trajectory t2 from trajectory t1 102 | """ 103 | dist = g_spd(t1, t2) + g_spd(t2, t1) 104 | return dist 105 | -------------------------------------------------------------------------------- /traj_dist/pydist/sspd.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maikol-solis/trajectory_distance/ecaae0e94ef5539c23cfcff3d23ec45f8a90982a/traj_dist/pydist/sspd.pyc -------------------------------------------------------------------------------- /trajectory_distance.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.0 2 | Name: trajectory-distance 3 | Version: 1.0 4 | Summary: Distance to compare trajectories in Cython 5 | Home-page: UNKNOWN 6 | Author: Brendan Guillouet 7 | Author-email: brendan.guillouet@gmail.com 8 | License: UNKNOWN 9 | Description: UNKNOWN 10 | Platform: UNKNOWN 11 | -------------------------------------------------------------------------------- /trajectory_distance.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | setup.py 2 | traj_dist/__init__.py 3 | traj_dist/distance.py 4 | traj_dist/example.py 5 | traj_dist/cydist/__init__.py 6 | traj_dist/cydist/basic_euclidean.pyx 7 | traj_dist/cydist/basic_geographical.pyx 8 | traj_dist/cydist/discret_frechet.pyx 9 | traj_dist/cydist/dtw.pyx 10 | traj_dist/cydist/edr.pyx 11 | traj_dist/cydist/erp.pyx 12 | traj_dist/cydist/frechet.pyx 13 | traj_dist/cydist/hausdorff.pyx 14 | traj_dist/cydist/lcss.pyx 15 | traj_dist/cydist/segment_distance.pyx 16 | traj_dist/cydist/sowd.pyx 17 | traj_dist/cydist/sspd.pyx 18 | traj_dist/pydist/__init__.py 19 | traj_dist/pydist/basic_euclidean.py 20 | traj_dist/pydist/basic_geographical.py 21 | traj_dist/pydist/discret_frechet.py 22 | traj_dist/pydist/dtw.py 23 | traj_dist/pydist/edr.py 24 | traj_dist/pydist/erp.py 25 | traj_dist/pydist/frechet.py 26 | traj_dist/pydist/hausdorff.py 27 | traj_dist/pydist/lcss.py 28 | traj_dist/pydist/linecell.py 29 | traj_dist/pydist/segment_distance.py 30 | traj_dist/pydist/sowd.py 31 | traj_dist/pydist/sspd.py 32 | trajectory_distance.egg-info/PKG-INFO 33 | trajectory_distance.egg-info/SOURCES.txt 34 | trajectory_distance.egg-info/dependency_links.txt 35 | trajectory_distance.egg-info/pbr.json 36 | trajectory_distance.egg-info/requires.txt 37 | trajectory_distance.egg-info/top_level.txt -------------------------------------------------------------------------------- /trajectory_distance.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /trajectory_distance.egg-info/pbr.json: -------------------------------------------------------------------------------- 1 | {"is_release": false, "git_version": "a32bc39"} -------------------------------------------------------------------------------- /trajectory_distance.egg-info/requires.txt: -------------------------------------------------------------------------------- 1 | numpy>=1.9.1 2 | cython>=0.21.2 3 | shapely>=1.5.6 4 | Geohash 5 | -------------------------------------------------------------------------------- /trajectory_distance.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | traj_dist 2 | --------------------------------------------------------------------------------