Трета задача:
разширеното евклидово
пространство
„ Програмиране с 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)