def ZeroCheck(cN): if cN == complex(0,0): return complex(1,0) else: return cN def c_tr(cN): return cN.real, cN.imag def cNorm(cN): return ZeroCheck(cN)/abs(ZeroCheck(cN)) def cDot(cA, cB): return (cA * cB.conjugate()).real def cDist(cA, cB): return abs(cA-cB) def MobiusAdd(cA, cB): return (cA + cB) / (1 + cA.conjugate() * cB) def MobiusGyr(cA, cB): return (1 + cA * cB.conjugate()) / (1 + cA.conjugate() * cB) def MobiusAddGyr(cA, cB): return MobiusAdd(cA, cB), MobiusGyr(cA, cB) def Poincare2Klein(cN): return 2*cN / (1 + cDot(cN,cN)) class GyroVector: def __init__(self, cPos, cRot): self.cPos = complex(cPos) self.cRot = complex(cRot) self.normalize() def __add__(gA, gB): cAdd, cGyr = MobiusAddGyr(gA.cPos, gB.cPos * (1 / gA.cRot)) return GyroVector(cAdd, gA.cRot * gB.cRot * cGyr) def __neg__(self): return GyroVector(-(self.cRot * self.cPos), 1/self.cRot) def __sub__(gA, gB): return gA + (-gB) def copy(self): return GyroVector(self.cPos,self.cRot) def normalize(self): if abs(self.cPos) > 1: self.cPos = cNorm(self.cPos) self.cRot = cNorm(self.cRot) def rotate(self,cRot): self.cRot *= cRot def transform(self, cA): #cAdd, cGyr = MobiusAddGyr(self.cPos, cA / ZeroCheck(self.cRot)) cAdd, cGyr = MobiusAddGyr(self.cPos, cA / self.cRot) self.cPos = cAdd self.cRot = self.cRot * cGyr def transformed(self, cA): #cAdd, cGyr = MobiusAddGyr(self.cPos, cA / ZeroCheck(self.cRot)) #return GyroVector(cAdd, self.cRot * cGyr) return gA.copy().transform(cA) def nrtransformed(self, cA): return MobiusAdd(self.cPos, cA / self.cRot)