Package symserv :: Module symOperators
[hide private]
[frames] | no frames]

Source Code for Module symserv.symOperators

  1  ######################################################################## 
  2  # 
  3  # Date: Nov 2001 Authors: Daniel Stoffler, Michel Sanner 
  4  # 
  5  #    stoffler@scripps.edu 
  6  #    sanner@scripps.edu 
  7  # 
  8  #       The Scripps Research Institute (TSRI) 
  9  #       Molecular Graphics Lab 
 10  #       La Jolla, CA 92037, USA 
 11  # 
 12  # Copyright: Daniel Stoffler, Michel Sanner and TSRI 
 13  # 
 14  ######################################################################### 
 15   
 16  from mglutil.math.rotax import rotax 
 17  from mglutil.math.transformation import Transformation 
 18  import Numeric, math, string 
 19   
 20   
21 -class SymNFold:
22 """ vector: list of floats [x, y, z] 23 point: list of floats [x, y, z] 24 symmetry int, >= 1 25 identity: int, 0 or 1 26 """ 27
28 - def __init__(self, vector, point, symmetry, identity):
29 self.set(vector, point, symmetry, identity)
30 31
32 - def getMatrices(self):
33 angle=360.0/self.symmetry 34 m=[] 35 t=Numeric.array(self.point)*-1 36 37 if self.identity == 1: 38 mat = Numeric.identity(4).astype('f') 39 m.append(mat) 40 41 T = Transformation(trans=t) 42 T1 = T.inverse() 43 for i in range(self.symmetry-1): 44 newList=[] 45 newList.extend(list(self.vector)) 46 newList.append(angle) 47 48 R = Transformation(quaternion=newList) 49 50 mt = T1 * R * T 51 #newmat = mt.getMatrix() 52 newmat = mt.getDejaVuMatrix() 53 m.append(newmat) 54 angle=angle+360.0/self.symmetry 55 56 return m
57 58
59 - def set(self, vector=None, point=None, symmetry=None, identity=None):
60 if vector: 61 assert len(vector)==3 62 self.vector = Numeric.array(vector).astype('f') 63 if point: 64 assert len(point)==3 65 self.point = Numeric.array(point).astype('f') 66 if symmetry: 67 assert symmetry >= 1 68 self.symmetry = symmetry 69 if identity is not None: 70 assert identity in (0,1) 71 self.identity = identity
72 73
74 - def __call__(self, inMatrices, applyIndex=None):
75 """outMatrices <- SymNFold(inMatrices, applyIndex=None) 76 inMatrices: list of 4x4 matrices 77 outMatrices: list of 4x4 matrices 78 if applyIndex is given it should be a list of 0-based indices of 79 matrices to which this operator's transformation will be applied. 80 """ 81 82 if not inMatrices: inMatrices = [Numeric.identity(4).astype('f')] 83 matrices = Numeric.array(inMatrices) 84 assert len(matrices.shape)==3 85 assert matrices.shape[-2] == 4 and matrices.shape[-1] == 4 86 ownmat = self.getMatrices() 87 out = [] 88 for m in ownmat: # loop over this node's own transformation matrices 89 for im in matrices: #loop over node's incoming matrices 90 out.append( Numeric.matrixmultiply(m, im) ) 91 return out
92 93
94 -class SymTrans:
95
96 - def __init__(self, vector=(1.0, 0.0, 0.0), length=0.0, identity=0):
97 self.vector = vector 98 self.length = length 99 self.identity = identity
100 101
102 - def getMatrices(self):
103 m=[] 104 mat=Numeric.identity(4).astype('f') 105 106 if self.length is None or self.length == 0: 107 m.append( Numeric.identity(4).astype('f') ) 108 return m 109 110 if self.identity == 1: 111 m.append( Numeric.identity(4).astype('f') ) 112 113 mat[:3, 3] = (self.vector*self.length).astype('f') 114 m.append(mat) 115 return m
116 117
118 - def set(self, vector=None, identity=None, length=None):
119 if vector: 120 assert len(vector)==3 121 self.vector = Numeric.array(vector).astype('f') 122 if identity is not None: 123 assert identity in (0,1) 124 self.identity = identity 125 if length is not None: 126 self.length = float(length)
127 128
129 - def __call__(self, inMatrices, applyIndex=None):
130 """outMatrices <- SymTrans(inMatrices, applyIndex=None) 131 inMatrices: list of 4x4 matrices 132 outMatrices: list of 4x4 matrices 133 """ 134 135 if not inMatrices: inMatrices = [Numeric.identity(4).astype('f')] 136 matrices = Numeric.array(inMatrices) 137 assert len(matrices.shape)==3 138 assert matrices.shape[-2] == 4 and matrices.shape[-1] == 4 139 ownmat = self.getMatrices() 140 out = [] 141 for m in ownmat: # loop over this node's own transformation matrices 142 for im in matrices: #loop over node's incoming matrices 143 out.append( Numeric.matrixmultiply(m, im) ) 144 return out
145 146 147
148 -class SymTransXYZ:
149
150 - def __init__(self, data, identity):
151 self.set(data, identity)
152
153 - def set(self, data=None, identity=None):
154 if data: 155 assert len(data)==6 156 self.vector1 = Numeric.array(data[3]).astype('f')*float(data[0]) 157 self.vector2 = Numeric.array(data[4]).astype('f')*float(data[1]) 158 self.vector3 = Numeric.array(data[5]).astype('f')*float(data[2]) 159 if identity is not None: 160 assert identity in (0,1) 161 self.identity = identity
162 163
164 - def getMatrices(self):
165 m=[] 166 t1=Numeric.array(self.vector1)#*-1 #FIXME: why did we do this? 167 t2=Numeric.array(self.vector2)#*-1 168 t3=Numeric.array(self.vector3)#*-1 169 170 if self.identity == 1: 171 mat = Numeric.identity(4).astype('f') 172 m.append(mat) 173 174 175 T1 = Transformation(trans=t1) 176 T2 = Transformation(trans=t2) 177 T3 = Transformation(trans=t3) 178 179 mt = T1*T2*T3 180 newmat = mt.getMatrix() 181 m.append(newmat) 182 183 return m
184 185
186 - def __call__(self, inMatrices, applyIndex=None):
187 """outMatrices <- SymRot(inMatrices, applyIndex=None) 188 inMatrices: list of 4x4 matrices 189 outMatrices: list of 4x4 matrices 190 """ 191 192 if not inMatrices: inMatrices = [Numeric.identity(4).astype('f')] 193 matrices = Numeric.array(inMatrices) 194 assert len(matrices.shape)==3 195 assert matrices.shape[-2] == 4 and matrices.shape[-1] == 4 196 ownmat = self.getMatrices() 197 out = [] 198 for m in ownmat: # loop over this node's own transformation matrices 199 for im in matrices: #loop over node's incoming matrices 200 out.append( Numeric.matrixmultiply(m, im) ) 201 return out
202 203 204
205 -class SymRot:
206
207 - def __init__(self, vector, point, angle, identity):
208 self.set(vector, point, angle, identity)
209 210
211 - def getMatrices(self):
212 m=[] 213 t=Numeric.array(self.point)*-1 214 215 if self.identity == 1: 216 mat = Numeric.identity(4).astype('f') 217 m.append(mat) 218 219 newList=[] 220 newList.extend(list(self.vector)) 221 newList.append(self.angle) 222 223 T = Transformation(trans=t) 224 R = Transformation(quaternion=newList) 225 226 mt = T.inverse() * R * T 227 newmat = mt.getMatrix() 228 m.append(newmat) 229 230 return m
231 232
233 - def set(self, vector=None, point=None, angle=None, identity=None):
234 if vector: 235 assert len(vector)==3 236 self.vector = Numeric.array(vector).astype('f') 237 if point: 238 assert len(point)==3 239 self.point = Numeric.array(point).astype('f') 240 if angle is None: self.angle = 0.0 241 elif angle is not None: 242 self.angle = angle 243 if identity is not None: 244 assert identity in (0,1) 245 self.identity = identity
246 247
248 - def __call__(self, inMatrices, applyIndex=None):
249 """outMatrices <- SymRot(inMatrices, applyIndex=None) 250 inMatrices: list of 4x4 matrices 251 outMatrices: list of 4x4 matrices 252 """ 253 254 if not inMatrices: inMatrices = [Numeric.identity(4).astype('f')] 255 matrices = Numeric.array(inMatrices) 256 assert len(matrices.shape)==3 257 assert matrices.shape[-2] == 4 and matrices.shape[-1] == 4 258 ownmat = self.getMatrices() 259 out = [] 260 for m in ownmat: # loop over this node's own transformation matrices 261 for im in matrices: #loop over node's incoming matrices 262 out.append( Numeric.matrixmultiply(m, im) ) 263 return out
264 265
266 -class SymScale:
267
268 - def getMatrices(self, scaleFactor, selection=[1, 1, 1]):
269 mat = Numeric.identity(4).astype('f') 270 # apply scale factor to x, y and/or z 271 272 if selection[0] not in [0, False]: 273 mat[0][0] = scaleFactor 274 else: 275 mat[0][0] = 1.0 276 277 if selection[1] not in [0, False]: 278 mat[1][1] = scaleFactor 279 else: 280 mat[1][1] = 1.0 281 282 if selection[2] not in [0, False]: 283 mat[2][2] = scaleFactor 284 else: 285 mat[2][2] = 1.0 286 287 return mat
288 289
290 - def __call__(self, inMatrices, scaleFactor, applyIndex=None, selection=[True,True,True]):
291 """outMatrices <- SymScale(inMatrices, applyIndex=None, selection=[1,1,1]) 292 inMatrices: list of 4x4 matrices 293 outMatrices: list of 4x4 matrices 294 (selection: scale x,y, and/or z) can be 1,True or 0,False) 295 """ 296 297 if not inMatrices: 298 inMatrices = [Numeric.identity(4).astype('f')] 299 300 matrices = Numeric.array(inMatrices) 301 assert len(matrices.shape)==3 302 assert matrices.shape[-2] == 4 and matrices.shape[-1] == 4 303 ownmat = self.getMatrices(scaleFactor, selection) 304 out = [] 305 for im in matrices: #loop over node's incoming matrices 306 out.append( Numeric.matrixmultiply(im, ownmat) ) 307 return out
308 309
310 -class SymHelix:
311 """ 312 Operator to build a stream of transforamtion matrices describing a helical 313 arrangment. 314 315 arguments: 316 vector: the 3-D vector defining the oriention of the helical axis 317 point: a 3-D point defining the location in space of the helical axis 318 angle: angular value in degrees between 2 consecutive copies 319 hrise: displacement along the helical axis between 2 consecutive copies 320 copies: number of transformations 321 """
322 - def __init__(self, vector, point, angle, hrise, copies):
323 self.copies = 1 324 self.hrise = 0 325 self.angle = 0 326 self.point = (0.,0.,0.) 327 self.vector = (0.,1.,0.) 328 self.set(vector, point, angle, hrise, copies)
329 330
331 - def normalize(self, v):
332 nv = float(math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2])) 333 return (v[0]/nv, v[1]/nv, v[2]/nv)
334 335
336 - def set(self, vector=None, point=None, angle=None, hrise=None, 337 copies=None):
338 339 if vector is not None: 340 assert len(vector)==3 341 self.vector = self.normalize(vector) 342 343 if point is not None: 344 assert len(vector)==3 345 self.point = point 346 347 if angle is not None: 348 self.angle = angle*math.pi/180. 349 350 if hrise is not None: 351 self.hrise = hrise 352 353 if copies is not None: 354 assert copies >= 1 355 self.copies=copies
356 357
358 - def getMatrices(self):
359 matrices = [] 360 r = self.hrise 361 v = self.vector 362 p = self.point 363 rv = (r*v[0], r*v[1], r*v[2]) 364 365 ## does not work .. some weird problem with the angle (MS) 366 # build one increment of transformation 367 ## R = Transformation( 368 ## trans=[rv[0], rv[1], rv[2]], 369 ## quaternion=[v[0], v[1], v[2], self.angle*180/math.pi]) 370 ## T = Transformation(trans=self.point) 371 ## transform1 = T * R * T.inverse() 372 ## transform = T * R * T.inverse() 373 ## matrices.append( transform.getMatrix() ) 374 ## for i in range(self.copies-1): 375 ## transform = transform*transform1 376 ## matrices.append( transform.getMatrix() ) 377 378 # build rotation and translation matrix about helical axis going 379 # rot matrix C style 380 R = rotax( p, [p[0]+v[0], p[1]+v[1], p[2]+v[2]], 381 self.angle, False) 382 riseMat = Numeric.identity(4).astype('f') 383 riseMat[:3, 3] = rv # add the rise 384 transform = Numeric.matrixmultiply(riseMat, R) 385 N = Numeric 386 387 matrices.append( N.identity(4).astype('f')) 388 for i in range(1,self.copies): 389 mat = matrices[i-1] 390 mat = Numeric.matrixmultiply(mat, transform) 391 matrices.append(mat) 392 393 return matrices
394 395
396 - def __call__(self, inMatrices, applyIndex=None):
397 """outMatrices <- SymHelix(inMatrices, applyIndex=None) 398 inMatrices: list of 4x4 matrices 399 outMatrices: list of 4x4 matrices 400 """ 401 402 if not inMatrices: inMatrices = [Numeric.identity(4).astype('f')] 403 matrices = Numeric.array(inMatrices) 404 assert len(matrices.shape)==3 405 assert matrices.shape[-2] == 4 and matrices.shape[-1] == 4 406 ownmat = self.getMatrices() 407 out = [] 408 for m in ownmat: # loop over this node's own transformation matrices 409 for im in matrices: #loop over node's incoming matrices 410 out.append( Numeric.matrixmultiply(m, im) ) 411 return out
412 413
414 -class SymMerge:
415
416 - def __init__(self):
417 pass
418
419 - def getMatrices(self):
420 pass
421
422 - def set(self):
423 pass
424
425 - def __call__(self, inMatrices, applyIndex=None):
426 """outMatrices <- SymMerge(inMatrices, applyIndex=None) 427 inMatrices: list of 4x4 matrices 428 outMatrices: list of 4x4 matrices 429 """ 430 431 if not inMatrices: inMatrices = [Numeric.identity(4).astype('f')] 432 return inMatrices
433 434
435 -class SymMultiply:
436 """ SymMultiply multiplies incoming matrices and ouputs them. 437 - 1 parent is multiplied with itself 438 - 2 parents: two valid options: either one of the parents has 439 lenght 1 (1 matrix) which is then multiplied to all other matrices 440 of the second parent or both parents have the same amount of 441 matrices. """ 442 443
444 - def __init__(self):
445 pass
446 447
448 - def getMatrices(self, matA, matB):
449 450 matInA, matInB = self.set(matA, matB) 451 452 #assert that matrices have either size 1, or equal size 453 assert len(matInA) == 1 or len(matInB) == 1 or \ 454 len(matInA) == len(matInB) 455 456 matrixOut = [] 457 458 #now the actual multiplication 459 if len(matInA) == 1: 460 for i in range(len(matInB)): #loop over node's incoming matrices 461 matrixOut.append(Numeric.matrixmultiply(matInA[0], 462 matInB[i])) 463 464 elif len(matInB) == 1: 465 for i in range(len(matInA)): #loop over node's incoming matrices 466 matrixOut.append(Numeric.matrixmultiply(matInA[i], 467 matInB[0])) 468 469 470 else: 471 for i in range(len(matInA)): #loop over node's incoming matrices 472 matrixOut.append(Numeric.matrixmultiply(matInA[i], 473 matInB[i])) 474 475 return matrixOut
476 477
478 - def set(self, inA=None, inB=None):
479 480 if inA is None and inB is not None: 481 matInA = matInB = inB 482 elif inA is not None and inB is None: 483 matInA = matInB = inA 484 elif inA is not None and inB is not None: 485 matInA = inA 486 matInB = inB 487 elif inA is None and inB is None: 488 matInA = matInB = Numeric.identity(4).astype('f') 489 490 return matInA, matInB
491 492
493 - def __call__(self, matA=None, matB=None):
494 """outMatrices <- SymMerge(matA, matB) 495 matA: list of 4x4 matrices 496 matB: list of 4x4 matrices 497 outMatrices: list of 4x4 matrices 498 """ 499 500 out = self.getMatrices(matA, matB) 501 return out
502 503 504
505 -class SymSplit:
506 """unselected matrices of the incomming stream are sent to 507 output port 0, selected matrices are sent to additional output ports which get 508 created on selection. 509 selection is done by specifying matrices comma separated indices in the 510 incomming stream. Ranges can be specified using the ':' or '-' character. 511 additional ports are created by using the ';' character. 512 """ 513 514
515 - def __init__(self, matrices, chars):
516 self.set(matrices, chars)
517 518
519 - def set(self, matrices=None, chars=None):
520 self.inMatrices = matrices 521 self.indices = self.processString(chars)
522 523
524 - def processString(self, entry):
525 split1=[] 526 split2=[] 527 l=[] 528 ll=[] 529 newList=[] 530 split1=string.split(entry,';') 531 i=0 532 for i in range(len(split1)): 533 l=string.split(split1[i],',') 534 for item in l: 535 try: 536 val=int(item) 537 ll.append(val) 538 except: 539 for c in item: 540 if c == '-' or c == ':': 541 s=string.split(item,c) 542 newList=range(int(s[0]),int(s[1])+1) 543 for i in range(len(newList)): 544 ll.append(newList[i]) 545 546 split2.append(ll) 547 ll=[] 548 return split2
549 550
551 - def getMatrices(self):
552 outMatrices=[] 553 indicesComp = range(len(self.inMatrices)) 554 if self.indices[0] == []: 555 self.indices[0] = indicesComp 556 fullList = [] 557 else: 558 fullList = Numeric.concatenate(self.indices) 559 map( indicesComp.remove, fullList ) 560 self.indices.insert(0,indicesComp) 561 562 for i in range(len(self.indices)): 563 outMatrices.append(Numeric.take(self.inMatrices, self.indices[i])) 564 return outMatrices
565 566
567 - def __call__(self, inMatrices, applyIndex=None):
568 """outMatrices <- SymSplit(inMatrices, applyIndex=None) 569 inMatrices: list of 4x4 matrices 570 outMatrices: list of 4x4 matrices 571 """ 572 if not inMatrices: 573 outMatrices = [Numeric.identity(4).astype('f')] 574 else: 575 outMatrices = self.getMatrices() 576 return outMatrices
577 578
579 -class CenterOfMass:
580 """ imputs xyz coords, outputs center of gravity """ 581 582
583 - def __init__(self, coords):
584 self.set(coords)
585 586
587 - def set(self, coords=None):
588 self.coords = coords
589 590
591 - def compute(self):
592 if self.coords is None: 593 return [0., 0., 0.] 594 else: 595 self.coords=list(Numeric.sum(self.coords)/len(self.coords)) 596 return self.coords
597 598
599 - def __call__(self):
600 return self.compute()
601 602
603 -class SymOrient:
604 """ rotation around center of gravity """ 605
606 - def __init__(self, vector, angle, center, identity):
607 self.set(vector, angle, center, identity)
608 609
610 - def getMatrices(self):
611 m=[] 612 newList=[] 613 mat = Numeric.identity(4).astype('f') 614 if self.identity == 1: 615 m.append(mat) 616 617 newList.extend(list(self.vector)) 618 newList.append(self.angle) 619 t=Numeric.array(self.center)*-1 620 621 T = Transformation(trans=t) 622 R = Transformation(quaternion=newList) 623 624 mt = T.inverse() * R * T 625 newmat = mt.getMatrix() 626 627 m.append(newmat) 628 return m
629 630
631 - def set(self, vector=None, angle=None, center=None, identity=None):
632 if vector: 633 assert len(vector)==3 634 self.vector = vector 635 636 if angle is None: self.angle = 0.0 637 elif angle is not None: 638 self.angle=angle 639 640 if center is None: 641 center=[0.,0,0] 642 self.center=center 643 644 if identity is not None: 645 assert identity in (0,1) 646 self.identity = identity
647 648
649 - def __call__(self, inMatrices, applyIndex=None):
650 """outMatrices <- SymOrient(inMatrices, applyIndex=None) 651 inMatrices: list of 4x4 matrices 652 outMatrices: list of 4x4 matrices 653 """ 654 655 if not inMatrices: inMatrices = [Numeric.identity(4).astype('f')] 656 matrices = Numeric.array(inMatrices) 657 assert len(matrices.shape)==3 658 assert matrices.shape[-2] == 4 and matrices.shape[-1] == 4 659 ownmat = self.getMatrices() 660 out = [] 661 for m in ownmat: # loop over this node's own transformation matrices 662 for im in matrices: #loop over node's incoming matrices 663 out.append( Numeric.matrixmultiply(m, im) ) 664 return out
665 666 667 668
669 -class ApplyTransfToCoords:
670 """ applies matrices to coords and outputs transformed coords """ 671
672 - def __init__(self, coords, matrices):
673 pass
674
675 - def getMatrices(self):
676 pass
677
678 - def set(self, coords=None, matrices=None):
679 if coords is None: return 680 else: self.coords = Numeric.array(coords).astype('f') 681 if matrices is None: 682 self.matrices = [Numeric.identity(4).astype('f')] 683 else: 684 #assert matrices.shape[-2] == 4 and matrices.shape[-1] == 4 685 self.matrices = matrices
686 687
688 - def compute(self):
689 newCoords=[] 690 if self.coords is not None: 691 one = Numeric.ones( (self.coords.shape[0], 1), \ 692 self.coords.typecode() ) 693 c = Numeric.concatenate( (self.coords, one), 1 ) 694 695 696 for m in range(len(self.matrices)): 697 newCoords.append(Numeric.matrixmultiply(c, \ 698 Numeric.transpose(self.matrices[m]))[:, :3]) 699 return Numeric.concatenate(newCoords)
700 701
702 - def __call__(self):
703 return self.compute()
704 705 706
707 -class PDBtoMatrix:
708 """ inputs PDB file, parses MTRIXn records and returns a list of (4x4) 709 matrices. MTRIXn is the default PDB standard, however not everybody seems 710 to follow the standard, thus an optional keyword can be passed that 711 describes the matrix records in this non-standard PDB file.""" 712
713 - def __init__(self):
714 pass
715 716
717 - def getMatrices(self, mol=None, keyword='MTRIX'):
718 if mol is None: 719 return 720 721 matrices = [] 722 next = 0 723 724 lines = mol.data[0].parser.allLines 725 arr = Numeric.identity(4).astype('f') 726 727 for l in lines: 728 729 spl = string.split(l) 730 if spl[0][:-1] != keyword: continue 731 index = int(spl[0][-1:])-1 732 733 arr[index][0] = float(spl[2]) 734 arr[index][1] = float(spl[3]) 735 arr[index][2] = float(spl[4]) 736 737 if index == 2: 738 matrices.append(arr) 739 arr = Numeric.identity(4).astype('f') 740 741 return matrices
742 743 744
745 -class SymTranspose:
746 747 """ SymTranspose transposes all incomming matrices. """ 748 749
750 - def __call__(self, inMatrices=None, applyIndex=None):
751 """outMatrices <- SymTranspose(inMatrices, applyIndex=None) 752 inMatrices: list of 4x4 matrices 753 outMatrices: list of 4x4 matrices 754 """ 755 756 if not inMatrices: 757 inMatrices = [Numeric.identity(4).astype('f')] 758 759 matrices = Numeric.array(inMatrices) 760 assert matrices.shape[-2] == 4 and matrices.shape[-1] == 4 761 762 out = [] 763 for im in matrices: #loop over node's incoming matrices 764 out.append( Numeric.transpose(im) ) 765 return out
766
767 -class SymInverse:
768 769 """ SymInverse inverse all incomming matrices. """ 770 771
772 - def __call__(self, inMatrices=None, applyIndex=None):
773 """outMatrices <- SymInverse(inMatrices, applyIndex=None) 774 inMatrices: list of 4x4 matrices 775 outMatrices: list of 4x4 matrices 776 """ 777 778 import LinearAlgebra 779 780 if not inMatrices: 781 inMatrices = [Numeric.identity(4).astype('f')] 782 783 matrices = Numeric.array(inMatrices) 784 assert matrices.shape[-2] == 4 and matrices.shape[-1] == 4 785 786 out = [] 787 for im in matrices: #loop over node's incoming matrices 788 out.append( LinearAlgebra.inverse(im) ) 789 return out
790 791
792 -class DistanceBetweenTwoPoints:
793 794 """Compute the distance between two (x,y,z) points""" 795 796
797 - def __call__(self, point1, point2):
798 """point1, point2 799 both must be (x,y,z) coordinates""" 800 801 x1, y1, z1 = point1 802 x2, y2, z2 = point2 803 dist = math.sqrt( math.pow((x2-x1),2) + math.pow((y2-y1),2) + \ 804 math.pow((z2-z1),2) ) 805 return dist
806