point3.py

'''\
Python 3D Point Class.

Extending the 2D Point class to three dimensions.
The sub-class adds a Z coordinate to the implementation
and an Elevation angle to the polar coordinates.

Developer@Sonnack.com
April 2010
'''
####################################################################################################
from sys import stdoutstderrargv
import math
from point2 import point2
####################################################################################################


##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
## 3D POINT
##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class point3 (point2):
    '''A 3D Point Class based on the 2D Point Class.'''

    def __init__ (selfx=0y=0z=0):
        super(point3,self).__init__(x,y)
        self.z = z

    def reset (self):
        ''' Move the Point to 0,0,0. '''
        super(point3,self).reset()
        self.z = 0
        return self

    def set (selfx=0y=0z=0):
        ''' Move the Point to an absolute coordinate (x,y,z). '''
        super(point3,self).set(x,y)
        self.z = z
        return self

    def move (selfx=0y=0z=0):
        ''' Move the Point relative to itself (+x,+y,+z). '''
        super(point3,self).move(x,y)
        self.z += z
        return self


    def radius (self):
        ''' Radius: x^2 + y^2 + z^2 = r^2. '''
        return math.sqrt((self.x ** 2)+(self.y ** 2)+(self.z ** 2))

    def elevation (self):
        ''' Elevation: arc tangent of z/xy. '''
        xy = math.hypot(self.xself.y)
        return math.degrees(math.atan2(self.zxy))

    def distance (selfother):
        ''' Distance from one point to another. '''
        dx = math.fabs(self.x - other.x)
        dy = math.fabs(self.y - other.y)
        dz = math.fabs(self.z - other.z)
        return math.sqrt((dx*dx)+(dy*dy)+(dz*dz))


    def getList (self):
        ''' Return Point as a List object. '''
        return [self.xself.yself.z]

    def getTuple (self):
        ''' Return Point as a Tuple object. '''
        return (self.xself.yself.z)


    def coord (self):
        ''' Return pretty coordinate version. '''
        return "(%.3f,%.3f,%.3f)" % (self.xself.yself.z)

    def polar (self):
        ''' Return pretty polar version. '''
        return "[%.3f@%.3f@%.3f]" % (self.radius(), self.angle(), self.elevation())

    def __str__ (self):
        ''' Return pretty version. '''
        s = "%.4f,%.4f,%.4f"
        t = (self.xself.yself.z)
        return s % t

    def __repr__ (self):
        ''' Return Point as a serializable object (JSON). '''
        s = "{point3:{x:%f, y:%f, z:%f}}"
        t = (self.xself.yself.z)
        return s % t

    def __len__ (self):
        ''' A point's length is its radius as an integer. '''
        return int(self.radius())


    def __cmp__ (selfother):
        ''' Points compare equal if they are really close. '''
        diff = self.angle() - other.angle()
        # if angles are nearly the same, compare based on elevation...
        if math.fabs(diff) < self.tiny:
            diff = self.elevation() - other.elevation()
            # if elevations are nearly the same, compare based on radius...
            if math.fabs(diff) < self.tiny:
                diff = self.radius() - other.radius()
                # if the radii are nearly the same, just consider the points equal...
                if math.fabs(diff) < self.tiny:
                    return 0
        # if the difference sub-integer, use "hysteresis"...
        if int(diff) == 0:
            return -1 if (diff < 0else +1
        return int(diff)

    def __nonzero__ (self):
        ''' Point is non-zero if outside a tiny radius. '''
        offset = self.radius()
        if math.fabs(offset) < self.tiny:
            return True
        return False

##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
## POINT
##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~##
class point (point3):
    '''A generic alias.'''
    pass



##================================================================================================##
def demo1 ():
    ''' Just shows the Point in action.
        (And proves the class works.)
    '''
    p0 = point()
    p1 = point(101010)
    p2 = point(1020)
    p3 = point(10, -208)
    p4 = point(057)
    p5 = point(-10209)
    print p0p1p2p3p4p5
    print

    list_point3("P0"p0)
    list_point3("P1"p1)
    list_point3("P2"p2)
    list_point3("P3"p3)
    list_point3("P4"p4)
    list_point3("P5"p5)

    p1.reset()
    list_point3("P1.reset"p1)

    p1.set(-10,10,-5)
    list_point3("P1.set"p1)

    p1.move(1,1,1)
    list_point3("P1.move"p1)
    p1.move(1,1,1)
    list_point3("P1.move"p1)

    ps = [p0p1p2p3p4p5]
    print ps
    print
    print sorted(ps)
    return ps

##================================================================================================##
def list_point3 (sp):
    print "%s.coord: %.3f,%.3f,%.3f" % (sp.xp.yp.z)
    print "%s.polar: %.3f,%.3f,%.3f" % (sp.angle(), p.radius(), p.elevation())

####################################################################################################
if __name__ == "__main__":
    print 'autorun:',argv[0]
    obj = demo1()

####################################################################################################
'''eof'''