vectors.py :  » Language-Interface » PyScript » pyscript-0.6.1 » pyscript » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Language Interface » PyScript 
PyScript » pyscript 0.6.1 » pyscript » vectors.py
# Copyright (C) 2002-2006  Alexei Gilchrist and Paul Cochrane
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


# $Id: vectors.py,v 1.26 2006/04/24 14:22:40 paultcochrane Exp $

"""
Vectors
"""

__revision__ = '$Revision: 1.26 $'

# Originally written by Mario Chemnitz (ucla@hrz.tu-chemnitz.de)
# Cut back and reworked to suit pyscript

from math import sqrt,sin,cos,pi,atan2
from pyscript.base import PsObj

class Matrix:
    '''
    2x2 matrix class
    '''
    type = 'Matrix'
 
    def __init__(self, a=0.0, b=0.0, c=0.0, d=0.0):
        # / a b \
        # \ c d /
        self.data = [a, b, c, d]

    def body(self):
        """
        Return the postscript body
        """
        d = self.data
        
        #NB postscript uses transpose
        return "[%g %g %g %g]" % (d[0], d[2], d[1], d[3])

    def __add__(self, o):
        if isinstance(o, Matrix):
            return Matrix(self[0]+o[0], 
                    self[1]+o[1], 
                    self[2]+o[2], 
                    self[3]+o[3])
        else:
            raise TypeError, "non-matrix (%s) in matrix addition"\
                     % type(o)

    __radd__ = __add__
  
    def __sub__(self, o):
        if isinstance(o, Matrix):
            return Matrix(self[0]-o[0], 
                    self[1]-o[1], 
                    self[2]-o[2], 
                    self[3]-o[3])
        else:
            raise TypeError, "non-matrix (%s) in matrix subtraction"\
                    % type(o)

    def __rsub__(self, o):
        if isinstance(o, Matrix):
            return Matrix(o[0]-self[0], 
                    o[1]-self[1], 
                    o[2]-self[2], 
                    o[3]-self[3])
        else:
            raise TypeError, "non-matrix (%s) in right matrix subtraction"\
                    % type(o)

    def __neg__(self):
        return Matrix(-self[0], -self[1], -self[2], -self[3])
        
    def __len__(self):
        return 4

    def __getitem__(self, i):
        if i < (len(self)):
            return self.data[i]
        else:
            raise IndexError, "index reading error"
    
    def __setitem__(self, i, other):
        if i < (len(self)):
            self.data[i] = other
        else:
            raise IndexError, "index writing error"

    # reads entry from row i and column j: -> data element
    def __getslice__(self, i, j):
        if i<2 and j<2:
            return self.data[2*i+j]
        else:
            raise IndexError, "index reading error"

    # writes matrix element to row i and column j
    def __setslice__(self, i, j, wert):
        if i<2 and j<2:
            self.data[2*i+j] = wert
        else:
            raise IndexError, "index writing error"

    #E matrix multiplication (self*other): -> matrix or vector
    def __mul__(self, other):
        if isinstance(other, Matrix):
            tmp = Matrix()
            for i in range(2):
                for j in range(2):
                    for k in range(2):
                        tmp[i:j] = tmp[i:j]+self[i:k]*other[k:j]
            return tmp
        elif isinstance(other, P):
            tmp = P()
            for i in range(2):
                for k in range(2):
                    tmp[i] = tmp[i]+self[i:k]*other[k]
            return tmp      
        elif isinstance(other, (int, float)):
            tmp = Matrix()
            for i in range(len(self)):
                tmp[i] = self[i]*other
            return tmp
        else:
            raise TypeError, "m-n-error in matrix multiplication"
      
    # E operand for matrix multiplication is on the right (other*self):
    # -> matrix
    def __rmul__(self, other):
        if isinstance(other, Matrix):
            tmp = Matrix()
            for i in range(len(self)):
                tmp[i] = other*self[i]
            return tmp
        else:
            raise TypeError, "error in right matrix multiplication"

    def det(self):
        """
        Return the matrix determinant
        """
        return self[0]*self[3]-self[1]*self[2]

    def inverse(self):
        """
        Find the inverse of the matrix
        """

        d = self.det()

        if d == 0 : 
            raise ValueError, "determinant=0, cannot calc inverse"

        return Matrix(self[3], -self[1], -self[2], self[0])/float(d)


    def __div__(self, n):
        # only for numbers!
        assert isinstance(n, (int, float)), \
                "only division by numbers implemented"
        n = float(n)
        tmp = Matrix()
        for i in range(len(self)):
            tmp[i] = self[i]/n
        return tmp
  
# -------------------------------------------------------------------------
# P = Vector (relative to origin) ie a point
# -------------------------------------------------------------------------
class P(PsObj):
    """
    A Vector (or point)
    operations always return type 'P' vectors
    """

    point = [0, 0]

    def __init__(self, x = 0.0, y = 0.0, **options):

        self.point = [x, y]

        PsObj.__init__(self, **options)
        
    def __len__(self):
        return 2

    def __getitem__(self, i):
        if i < (len(self)):
            return self.point[i]
        else:
            raise IndexError, "index reading error"
    
    def __setitem__(self, i, other):
        if i < (len(self)):
            self.point[i] = other
        else:
            raise IndexError, "index writing error"

    def __add__(self, o):
        if isinstance(o, P):
            return P(self[0]+o[0], self[1]+o[1])
        elif isinstance(o, (float, int)):
            return P(self[0]+o, self[1]+o)
        else:
            raise TypeError, "non-vector (%s) in vector addition"\
                    % type(o)

    __radd__ = __add__

    def __sub__(self, o):
        if isinstance(o, P):
            return P(self[0]-o[0], self[1]-o[1])
        else:
            raise TypeError, "non-vector (%s) in vector subtraction"\
                    % type(o)

    def __rsub__(self, o):
        if isinstance(o, P):
            return P(o[0]-self[0], o[1]-self[1])
        else:
            raise TypeError, "non-vector (%s) in right vector subtraction"\
                    % type(o)

    def __neg__(self):
        return P(-self[0], -self[1])

    def __mul__(self, o):
        if isinstance(o, P):
            # Dot product
            return self[0]*o[0]+self[1]*o[1]
        elif isinstance(o, Matrix):
            raise TypeError, "other must not be a matrix"
        else:
            return P(self[0]*o, self[1]*o)

    def __rmul__(self, o):
        return P(self[0]*o, self[1]*o)

    def body(self):
        """
        return postscript as string
        """
        return "%g uu %g uu" % tuple(self)

    def __div__(self, o):
        # only for numbers!
        if isinstance(o, (float, int)):
            n = float(o)
            return P(self[0]/n, self[1]/n)
        else:
            raise TypeError, "Only division by numbers implemented"

    def _get_x(self):
        """
        Get the x coordinate
        """
        return self[0]
    x = property(_get_x, None)

    def _get_y(self):
        """
        Get the y coordinate
        """
        return self[1]
    y = property(_get_y, None)

    def _get_length(self):
        '''
        Return length of this vector
        (distance from origintopoint import 
        '''
        return sqrt(self*self)
    length = property(_get_length, None)

    def _get_U(self):
        '''
        Return unit vector pointing in same direction
        '''
        return self/float(self.length)
    U = property(_get_U, None)

    def _get_arg(self):
        """
        Get angle (argument) of the vector
        """
        return atan2(self.x, self.y)/pi*180
    arg = property(_get_arg, None)

    def cross(self, other):
        """
        Calculate the cross product of two vectors
        """
        if isinstance(other, P):
            tmp = P()
            tmp[0] = self[1]*other[2]-self[2]*other[1]
            tmp[1] = self[2]*other[0]-self[0]*other[2]
            return tmp
        else:
            raise TypeError, "non-vector (%s) in cross product" % type(other)

# -------------------------------------------------------------------------
# R = Vector (relative to last point) function dependent!
# -------------------------------------------------------------------------
class R(P):
    """
    Relative point vector
    """

    def __add__(self, o):
        if isinstance(o, (float, int)):
            return R(self[0]+o, self[1]+o)
        else:
            return P.__add__(self, o)
        
    def __mul__(self, o):
        if isinstance(o, (float, int)):
            return R(self[0]*o, self[1]*o)
        else:
            return P.__mul__(self, o)
        
    def __rmul__(self, o):
        
        return R(self[0]*o, self[1]*o)

    def __div__(self, o):
        # only for numbers!
        if isinstance(o, (float, int)):
            return R(self[0]/float(o), self[1]/float(o))
        else:
            raise TypeError, "Only division by numbers implemented"
    def __neg__(self):
        return R(-self[0], -self[1])

# -------------------------------------------------------------------------
# Unit vector
# -------------------------------------------------------------------------

def U(angle, r = 1):
    '''
    return a relative vector of length r in the given direction
    '''
    x = r*sin(angle/180.0*pi)
    y = r*cos(angle/180.0*pi)

    return R(x, y)

# -------------------------------------------------------------------------
# Unit vector
# -------------------------------------------------------------------------
def Cusp(p1, p2):
    '''
    Alignment aid returns P(p1.x, p2.y)
    '''
    return P(p1[0], p2[1])
    
    
# -------------------------------------------------------------------------

def Identity(p):
    '''
    function which does nothing
    '''
    # do it this way so we return a copy
    return P(p[0], p[1])


# -------------------------------------------------------------------------
class Bbox(object):
    """
    A Rectangular area defined by sw corner and width and height.
    which specifies a boundingbox.

    Has the same attributes (but read only) as Area::
    
          nw--n--ne
          |       |
          w   c   e
          |       |
          sw--s--se

    """

    sw = None
    width = 0
    height = 0 

    def __init__(self, **options):
        '''
        can pass a dict of atributes to set
        '''

        object.__init__(self)
        # this will raise an exception if class doesn't have attribute
        # I think this is good.
        prop = []
        for key, value in options.items():
            if isinstance(eval('self.__class__.%s'%key), property):
                prop.append((key, value))
            else:
                self.__class__.__setattr__(self, key, value)


    def _get_n(self):
        """
        Get the "north" point
        """
        return self.sw+P(self.width/2., self.height)
    n = property(_get_n)

    def _get_ne(self):
        """
        Get the "north-east" point
        """
        return self.sw+P(self.width, self.height)
    ne = property(_get_ne)

    def _get_e(self):
        """
        Get the "east" point
        """
        return self.sw+P(self.width, self.height/2.)
    e = property(_get_e)

    def _get_se(self):
        """
        Get the "south-east" point
        """
        return self.sw+P(self.width, 0)
    se = property(_get_se)

    def _get_s(self):
        """
        Get the "south" point
        """
        return self.sw+P(self.width/2., 0)
    s = property(_get_s)

    def _get_w(self):
        """
        Get the "west" point
        """
        return self.sw+P(0, self.height/2.)
    w = property(_get_w)

    def _get_nw(self):
        """
        Get the "north-west" point
        """
        return self.sw+P(0, self.height)
    nw = property(_get_nw)

    def _get_c(self):
        """
        Get the "centre" point
        """
        return self.sw+P(self.width/2., self.height/2.)
    c = property(_get_c)

    def is_set(self):
        '''
        Is the bounding box set with a value?
        '''
        if self.sw is None:
            return 0
        else:
            return 1

    def union(self, bbox, itoe = Identity):
        '''
        Expand this boundingbox to include bbox,
        passing bbox through itoe if supplied
        '''

        if not bbox.is_set():
            # if the supplied bbox is not set we have
            # nothing to do
            return

        
        ne = itoe(bbox.ne)
        sw = itoe(bbox.sw)
        nw = itoe(bbox.nw)
        se = itoe(bbox.se)
        

        xmin = min(ne[0], nw[0], se[0], sw[0])
        xmax = max(ne[0], nw[0], se[0], sw[0])
        ymin = min(ne[1], nw[1], se[1], sw[1])
        ymax = max(ne[1], nw[1], se[1], sw[1])
        
        #if self.is_set():

            #x1=min(self.sw[0],sw[0])
            #y1=min(self.sw[1],sw[1])
            #x2=max(self.ne[0],ne[0])
            #y2=max(self.ne[1],ne[1])

            #self.sw=P(x1,y1)
            #self.width=x2-x1
            #self.height=y2-y1
            
        #else:

            #self.sw=sw
            #self.width,self.height=ne-sw

        if self.is_set():
            x1 = min(self.sw[0], xmin)
            y1 = min(self.sw[1], ymin)
            x2 = max(self.ne[0], xmax)
            y2 = max(self.ne[1], ymax)

            self.sw = P(x1, y1)
            self.width = x2-x1
            self.height = y2-y1
            
        else:
            self.sw = P(xmin, ymin)
            self.width = xmax-xmin
            self.height = ymax-ymin
            
# vim: expandtab shiftwidth=4:
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.