def _axisDistance(self, axis, infinite=False): from chimera import angle, cross, Plane # shortest distance between lines is perpendicular to both... sDir = self.xformDirection() aDir = axis.xformDirection() if angle(sDir, aDir) in [0.0, 180.0]: # parallel return self._axisEndsDist(axis) shortDir = cross(sDir, aDir) # can use analytically shortest dist only if each axis # penetrates the plane formed by the other axis and the # perpendicular if not infinite: for a1, a2 in [(axis, self), (self, axis)]: normal = cross(a1.xformDirection(), shortDir) plane = Plane(a1.xformCenter(), normal) d1 = plane.distance(a2.xformCenter() + a2.xformDirection() * a2.extents[0]) d2 = plane.distance(a2.xformCenter() + a2.xformDirection() * a2.extents[1]) if cmp(d1, 0.0) == cmp(d2, 0.0): # both ends on same side of plane return self._axisEndsDist(axis) # D is perpendicular distance to origin d1 = Plane(self.xformCenter(), shortDir).equation()[3] d2 = Plane(axis.xformCenter(), shortDir).equation()[3] return abs(d1 - d2)
def tetraPos(bondee, bonded, bondLen, toward=None, away=None, toward2=None, away2=None): newBonded = [] curBonded = bonded[:] if len(curBonded) == 0: pos = singlePos(bondee, bondLen, toward, away) toward = toward2 away = away2 newBonded.append(pos) curBonded.append(pos) if len(curBonded) == 1: # add at 109.5 degree angle coplanar = toward or away if coplanar: coplanar = [coplanar] else: coplanar = None pos = anglePos(bondee, curBonded[0], bondLen, 109.5, coplanar=coplanar) if toward or away: # find the other 109.5 position in the toward/away # plane and the closer/farther position as appropriate old = bondee - curBonded[0] old.normalize() new = pos - bondee midpoint = bondee + old * new.length * cos705 otherPos = pos + (midpoint - pos) * 2 d1 = (pos - (toward or away)).sqlength() d2 = (otherPos - (toward or away)).sqlength() if toward: if d2 < d1: pos = otherPos elif away and d2 > d1: pos = otherPos newBonded.append(pos) curBonded.append(pos) if len(curBonded) == 2: # add along anti-bisector of current bonds and raised up # 54.75 degrees from plane of those bonds (half of 109.5) v1 = curBonded[0] - bondee v2 = curBonded[1] - bondee v1.normalize() v2.normalize() antiBi = v1 + v2 antiBi.negate() antiBi.normalize() # in order to stabilize the third and fourth tetrahedral # positions, cross the longer vector by the shorter if v1.sqlength() > v2.sqlength(): crossV = cross(v1, v2) else: crossV = cross(v2, v1) crossV.normalize() antiBi = antiBi * cos5475 * bondLen crossV = crossV * sin5475 * bondLen pos = bondee + antiBi + crossV if toward or away: otherPos = bondee + antiBi - crossV d1 = (pos - (toward or away)).sqlength() d2 = (otherPos - (toward or away)).sqlength() if toward: if d2 < d1: pos = otherPos elif away and d2 > d1: pos = otherPos newBonded.append(pos) curBonded.append(pos) if len(curBonded) == 3: unitized = [] for cb in curBonded: v = cb - bondee v.normalize() unitized.append(bondee + v) pl = Plane(unitized) norm = pl.normal # if normal on other side of plane from bondee, we need to # invert the normal; the (signed) distance from bondee # to the plane indicates if it is on the same side # (positive == same side) d = pl.distance(bondee) if d < 0.0: norm.negate() newBonded.append(bondee + norm * bondLen) return newBonded