def simplexInCenter(vs): print " in simplexInCenter" n = len(vs) nDims = len(vs[0]) # 5 points in 2 dims is hopeless if n >= nDims+3: print " hopeless!" print " out simplexInCenter" return None weights = [] for i in xrange(n): oppositeFacet = Mat([vs[j] for j in xrange(n) if j != i]) #do('oppositeFacet') M = Mat([v-oppositeFacet[0] for v in oppositeFacet[1:]]) #do('M') M2 = M * M.transposed() #do('M2') det = M2.det() #do('det') oppositeFacetContent = sqrt(det) weights.append(oppositeFacetContent) weights = Vec(weights) weights /= sum(weights) answer = Vec(weights) * Mat(vs) do('answer') print " out simplexInCenter" return answer
def compose(self,rhs): lhs = self nDims = len(self.t) t = rhs.apply(self.t) # = rhs(lhs(0)) if True: R = Mat.identity(nDims) for i in xrange(nDims): R[i] = translate(rhs.apply(lhs.apply(R[i])), -t) # R[i] = Isometry(I,t)^-1(rhs(lhs(I[i]))) R = Mat(R) else: # Argh, I thought this was right, but it's not?? wtf? R = self.R * rhs.R return HyperbolicIsometry(R,t)
def inCenter4(vs): vs = [Vec(v) for v in vs] n = len(vs) assert n == 4 inwardNormals = [(vs[(i+1)%n]-vs[i]).perpDot().normalized() for i in xrange(n)] offsets = [inwardNormals[i].dot(vs[i]) for i in xrange(n)] if use_numpy: M = numpy.matrix([ list(inwardNormals[0])+[1,0], list(inwardNormals[1])+[0,1], list(inwardNormals[2])+[1,0], list(inwardNormals[3])+[0,1], ]) xyrr = numpy.linalg.solve(M,offsets) else: M = Mat([ list(inwardNormals[0])+[1,0], list(inwardNormals[1])+[0,1], list(inwardNormals[2])+[1,0], list(inwardNormals[3])+[0,1], ]) xyrr = M.inverse() * Vec(offsets) x,y,r,R = xyrr return Vec(x,y)
def __init__(self,R=None,t=None): # R and t can't both be None, or we wouldn't know the dimension if R == None: R = Mat.identity(len(t)) if t == None: t = [0]*len(R) self.R = Mat(R) self.t = Vec(t)
def identity(nDims): return HyperbolicIsometry(Mat.identity(nDims), [0]*nDims)
class HyperbolicIsometry: @staticmethod def identity(nDims): return HyperbolicIsometry(Mat.identity(nDims), [0]*nDims) def __init__(self,R=None,t=None): # R and t can't both be None, or we wouldn't know the dimension if R == None: R = Mat.identity(len(t)) if t == None: t = [0]*len(R) self.R = Mat(R) self.t = Vec(t) def apply(self,p): return translate(p * self.R, self.t) def applyInverse(self,p): return self.R * translate(p,-self.t) # R * p = p * R^-1 since R is orthogonal # Return f such that for all p, # f(p) = rhs(self(p)) def compose(self,rhs): lhs = self nDims = len(self.t) t = rhs.apply(self.t) # = rhs(lhs(0)) if True: R = Mat.identity(nDims) for i in xrange(nDims): R[i] = translate(rhs.apply(lhs.apply(R[i])), -t) # R[i] = Isometry(I,t)^-1(rhs(lhs(I[i]))) R = Mat(R) else: # Argh, I thought this was right, but it's not?? wtf? R = self.R * rhs.R return HyperbolicIsometry(R,t) def inverse(self): return HyperbolicIsometry(None,-self.t).compose(HyperbolicIsometry(self.R.transposed(),None)) def dist2(self,rhs): return (rhs.R-self.R).length2() + (rhs.t-self.t).length2() def __repr__(self): return 'HyperbolicIsometry('+`self.R`+','+`self.t`+')' def __str__(self): return self.__repr__() # # Operator notation: # f(p) = f.apply(p) # p*f = f.apply(p) # f0*f1 = f0.compose(f1) # note that # (f0*f1)*f2 == f0*(f1*f2) # and (p*f0)*f1 == p*(f0*f1) # def __call__(self,p): return self.apply(p) def __rmul__(self,lhs): # actually relies on fact that Vec's __mul__ # explicitly calls rhs.__rmul__ when rhs is unrecognized type return self.apply(lhs) def __mul__(self,rhs): return self.compose(rhs) def __pow__(self,rhs): assert type(rhs) == int if rhs == -1: # most common case return self.inverse() if rhs < 0: # either of the following work if True: return (self^-rhs).inverse() else: return self.inverse()^-rhs if rhs > 1: return self**int(rhs/2) * self**(rhs-int(rhs/2)) if rhs == 1: return self assert rhs == 0 return HyperbolicIsometry.identity(len(self.t)) # XXX TODO: I think this is a bad idea, since ^ binds looser than * and even + def __xor__(self,rhs): return self.__pow__(rhs)
def inCenter(vs): if False: do('vs') vs = [Vec(v) for v in vs] n = len(vs) inwardNormals = [(vs[(i+1)%n]-vs[i]).perpDot().normalized() for i in xrange(n)] offsets = [inwardNormals[i].dot(vs[i]) for i in xrange(n)] # compute n-2 tri-side in-centers... centers = [] radii = [] for i in xrange(n-2): if use_numpy: M = numpy.matrix([ list(inwardNormals[ 0 ])+[-1], list(inwardNormals[i+1])+[-1], list(inwardNormals[i+2])+[-1], ]) o = numpy.matrix([ [offsets[ 0 ]], [offsets[i+1]], [offsets[i+2]], ]) #x,y,r = numpy.linalg.solve(M,o) x,y,r = [float(x) for x in numpy.linalg.solve(M,o)] else: M = Mat([ list(inwardNormals[ 0 ])+[-1], list(inwardNormals[i+1])+[-1], list(inwardNormals[i+2])+[-1], ]) o = Vec([ offsets[ 0 ], offsets[i+1], offsets[i+2], ]) x,y,r = M.inverse() * o if False: # FUDGE r = abs(r) centers.append(Vec(x,y)) radii.append(r) if False: #do('x') #do('y') do('r') if n == 3: # single weight will be zero in this case... no point in doing the undefined arithmetic return centers[0] if n == 4: # Either way works, but neither way is robust when cocircular if False: weights = [ 1./(inwardNormals[3].dot(centers[0]) - offsets[3] - radii[0]), 1./(inwardNormals[n-3].dot(centers[n-2-1])-offsets[n-3] - radii[n-2-1]) ] else: weights = [ inwardNormals[1].dot(centers[1])-offsets[1] - radii[1], inwardNormals[3].dot(centers[0])-offsets[3] - radii[0], ] # fudge-- this shouldn't be needed, if I get a more robust formula to begin with if weights[0] == 0. and weights[1] == 0.: weights = [1.,1.] if n == 5: # I fear this doesn't really work weights = [ (inwardNormals[1].dot(centers[1])-offsets[1] - radii[1])*(inwardNormals[2].dot(centers[2])-offsets[2] - radii[2]), (inwardNormals[2].dot(centers[2])-offsets[2] - radii[2])*(inwardNormals[3].dot(centers[0])-offsets[3] - radii[0]), (inwardNormals[3].dot(centers[0])-offsets[3] - radii[0])*(inwardNormals[4].dot(centers[1])-offsets[4] - radii[1]), ] if False: # XXX GET RID # weights other than first and last are # 1 / (distance from last side not involving that circle) / (distance from first side not involving that circle) for i in xrange(n-4): weights.append(1./((inwardNormals[1+i].dot(centers[1+i]) - offsets[1+i] - radii[1+i]) * (inwardNormals[4+i].dot(centers[1+i]) - offsets[4+i] - radii[1+i]) )) weightsSum = sum(weights) if weightsSum == 0.: return centers[0] # hack if False: do('[float(weight) for weight in weights]') do('weightsSum') do('[float(weight/weightsSum) for weight in weights]') return sum([center*(weight/weightsSum) for center,weight in zip(centers,weights)])