Трета задача:
разширеното евклидово
пространство

„ Програмиране с Python“, ФМИ

29.04.2010г.

Класове

class GeometricError(Exception):

    pass

class Vector:

    def __init__(self, x, y):
        self.x = x
        self.y = y
		
    def __repr__(self):
        return "Vector(%r, %r)" % (self.x , self.y)

class Vector:

    def __eq__(self, other):
        return isinstance(other, Vector) and \
            self.x == other.x and self.y == other.y

class Vector:

    def __add__(self, other):
        if isinstance(other, Vector):
            return Vector(self.x + other.x, self.y + other.y)
        else:
            return NotImplemented
			
    def __sub__(self, other):
        if isinstance(other, Vector):
            return self + -other
        else:
            return NotImplemented

class Vector:

    def __pos__(self):
        return self.scaled(1)

    def __neg__(self):
        return self.scaled(-1)

class Vector:

    def __mul__(self, other):
        if isinstance(other, Vector):
            return self.x*other.x + self.y*other.y
        elif isinstance(other, numbers.Real):
            return self.scaled(other)
        else:
            return NotImplemented

class Vector:

    def __rmul__(self, other):
        return self * other
		
    def __truediv__(self, num):
        if isinstance(other, numbers.Real): 
            return self.scaled(1/other)
        else:
            return NotImplemented

class Vector:

    def scaled(self, num):
        return Vector(self.x*num, self.y*num)

    def length(self):
        return (self*self) ** 0.5

    def normal(self):
        return Vector(self.y, -self.x) # or (-y, x)

class Vector:

    def normalized(self):
        length = self.length()
        if length == 0:
            raise GeometricError
        return Vector(self.x / length, self.y / length)

class Vector:

    def iscollinear(self, other):
        if self.iszero() or other.iszero():
            return True
        v1, v2 = self.normalized(), other.normalized()
        return v1 == v2 or v1 == -v2

    def isnormal(self, other):
        if self.iszero() or other.iszero():
            return True
        return self.normal().iscollinear(other)

class Vector:

    def isnormalized(self):
        return self.length() == 1

    def iszero(self):
        return self.x == 0 and self.y == 0

class Point:

    def __init__(self, x, y, z=1):
        if x == y == z == 0:
            raise GeometricError
        else:
            self.x = x
            self.y = y
            self.z = z
			
    def __repr__(self):
        return "Point(%r, %r, %r)" % (self.x, self.y, self.z)

class Point:

    def __eq__(self, other):
        if isinstance(other, Point):
            triplet1 = self.x, self.y, self.z
            triplet2 = other.x, other.y, other.z
            return homogenous_coord_eq(triplet1, triplet2)
        else:
            return False

Помощни функции

def homogenous_coord_eq(triplet1, triplet2):
    """
    The homogenous coordinate triplets
    (a1, a2, a3), (b1, b2, b3) are equal iff:

    |a2 a3| = |a3 a1| = |a1 a2| = 0
    |b2 b3|   |b3 b1|   |b1 b2|
    """
    a1, a2, a3 = triplet1[0], triplet1[1], triplet1[2]
    b1, b2, b3 = triplet2[0], triplet2[1], triplet2[2]
    D = determinant
    return D(a2,a3,b2,b3) == D(a3,a1,b3,b1) == D(a1,a2,b1,b2) == 0

Помощни функции

def determinant(a1, a2, b1, b2):
    """
    Returns the value of the determinant:
    |a1 a2|
    |b1 b2|
    """
    return a1*b2 - a2*b1

class Point:

    def distance(self, other):
        if isinstance(other, Line):
            return other.distance(self)
        elif isinstance(other, Point) and self.z != 0 and other.z != 0:
            diffx, diffy = self._x()-other._x(), self._y()-other._y()
            return Vector(diffx, diffy).length()
        else:
            raise GeometricError

class Point:

    def _x(self):
        return self.x / self.z

    def _y(self):
        return self.y / self.z

class Line:

    def __init__(self, a, b):
        if isinstance(a, Point) and isinstance(b, Point):
            if a.isinfinite() and b.isinfinite():
                self.__init_infiniteline()
            elif a.isinfinite():
                self.__init_pointvector(b, Vector(a.x, a.y))
            elif b.isinfinite():
                self.__init_pointvector(a, Vector(b.x, b.y))
            else:
                self.__init_pointpoint(a, b)
        elif isinstance(a, Point) and isinstance(b, Vector):
            if a.isinfinite():
                self.__init_infiniteline()
            else:
                self.__init_pointvector(a, b)
        elif isinstance(a, Vector) and isinstance(b, Point):
            Line.__init__(self, b, a)
        else:
            raise GeometricError

class Line:

    def __init_infiniteline(self):
        self.a = 0
        self.b = 0
        self.c = 1
    
    def __init_pointvector(self, point, vector):
        point_offset = \
            Point(point.x + vector.x*point.z, point.y + vector.y*point.z)
        self.__init_pointpoint(point, point_offset)

class Line:

    def __init_pointpoint(self, point1, point2):
        assert(not point1.isinfinite() and not point2.isinfinite())
        if point1 == point2:
            raise GeometricError
        point1, point2 = point1.scaled(point2.z), point2.scaled(point1.z)
        self.a = point2.y - point1.y
        self.b = point1.x - point2.x
        self.c = -(self.a*point1.x + self.b*point1.y) / point1.z

class Line:

    def __repr__(self):
        if self.isinfinite():
            return "Line(Point(0,1,0), Point(1,0,0))"
        else:
            vector = Vector(-self.b, self.a)
            point1 = Point(0, -self.c/self.b) if self.b != 0 else None
            point2 = Point(-self.c/self.a, 0) if self.a != 0 else None
            return "Line(%r, %r)" % (point1 or point2, vector)

class Line:

    def __eq__(self, other):
        if isinstance(other, Line):
            triplet1 = self.a, self.b, self.c
            triplet2 = other.a, other.b, other.c
            return homogenous_coord_eq(triplet1, triplet2)
        else:
            return False

class Line:

    def __contains__(self, point):
        if point.isinfinite():
            point_vector = Vector(point.x, point.y)
            line_vector = self.colinear_vector()
            return line_vector.iscollinear(point_vector)
        else:
            return self.distance(point) == 0

class Line:

    def __mul__(self, other):
        if not isinstance(other, Line):
            return NotImplemented
        if self == other:
            raise GeometricError
        a1, b1, c1 = self.a, self.b, self.c
        a2, b2, c2 = other.a, other.b, other.c
        D = determinant
        x = D(b1, c1, b2, c2)
        y = D(c1, a1, c2, a2)
        z = D(a1, b1, a2, b2)
        return Point(x, y, z)

class Line:

    def isparallel(self, other):
        return self == other or (self * other).isinfinite()
    
    def isinfinite(self):
        return self.a == 0 and self.b == 0

class Line:

    def distance(self, point):
        if point.isinfinite():
            raise GeometricError
        else:
            line_vector = Vector(self.a, self.b)
            return abs(self.a*point._x() + self.b*point._y() + self.c) \
                    / line_vector.length()

class Line:

    def colinear_vector(self):
        return self.normal_vector().normal()

    def normal_vector(self):
        return Vector(self.a, self.b)

Още въпроси?