Express subsequent face-bonded tetrahedra as rational numbers (p/q)
by Kirby Urner Jan 11, 2005

import math
from __future__ import division

def tetrahelix():
    Start with 4 vertices sqrt(2) interdistant
    v1 = tuple([Rat(i) for i in (0,0,0)])
    v2 = tuple([Rat(i) for i in (0,1,1)])
    v3 = tuple([Rat(i) for i in (1,0,1)])
    v4 = tuple([Rat(i) for i in (1,1,0)])
    a,b,c,d = [apply(Vector,i) for i in [v1,v2,v3,v4]]
    loop = True
    while loop:
        print "%s\n%s\n%s\n%s\n" % (a,b,c,d)
        # plot the apex of subsequent tet

        e = (a+b+c)*Rat(2,3) - d
        # lose whatever vertex is > sqrt(2) distant

        b,c,d = filter(lambda x: (e-x).length() < 1.5, [a,b,c,d])
        a = e
        if not raw_input("Again? (y/n)? ").upper()=="Y":
                loop = False

class Rat(object):
    I couldn't find my old version, so quickly recoded from scratch.
    It's stripped down -- no powering or reciprocation

    def __init__(self,num,denom=1):
        f = self._gcd(num,denom)
        self.num = num/f
        self.denom = denom/f
    def __mul__(self,other):
        if type(other) == type(1):
            return Rat(self.num*other, self.denom)
            return Rat(self.num*other.num, self.denom*other.denom)
    def __add__(self,other):
        f = self._lcm(self.denom, other.denom)
        return Rat(self.num*f/self.denom + other.num * f/other.denom, f)

    def __neg__(self):
        return Rat(-self.num, self.denom)

    def __sub__(self,other):
        return self + -other

    def _gcd(self,a,b):
        while b:
            a,b = b,a%b
        return a
    def _lcm(self,a,b):
        return (a*b)/self._gcd(a,b)

    def __float__(self):
        return self.num/self.denom
    def __repr__(self):
        return "(%s/%s)" % (self.num, self.denom)
class Vector(object):
    And yer classic vector object.  Again, I've coded this a million times
    (OK, maybe 7-10 times).  Again, I'm just including ops that get my
    tetrahelix demo to work

    def __init__(self,a,b,c):
        self.a = a
        self.b = b
        self.c = c

    def __add__(self, other):
        return Vector(self.a + other.a, self.b + other.b, self.c + other.c)

    def length(self):
        return math.sqrt(float(self.a*self.a + self.b*self.b + self.c*self.c))

    def __neg__(self):
        return Vector(-self.a, -self.b, -self.c)

    def __sub__(self, other):
        return self + -other

    def __mul__(self, k):
        return Vector(self.a * k, self.b * k, self.c * k)

    __rmul__ = __mul__
    def __repr__(self):
        return "Vector(%s, %s, %s)" % (self.a, self.b, self.c)
# code highlighted using py2html.py version 0.8