diff --git a/HISTORY b/HISTORY new file mode 100644 index 0000000..529cee9 --- /dev/null +++ b/HISTORY @@ -0,0 +1,16 @@ + +Oct 30, 2014 marchon added package to make installation easier + no core modifications, only + - README + - HISTORY + - DESCRIPTIONS + - REFERENCE + * PlanarUniversalGeometry.pdf + * Trigonometry-The-Study-Of-Circles.pdf + * Universal-Hyperbolic-Geometry-I-Trigonometry.pdf + * Universal-Hyperbolic-Geometry-II-A-pictorial-overview.pdf + * Universal-Hyperbolic-Geometry-Summary-of-NJWildbergers-online-lecture-series.pdf + * WhyEllipsesAreNotEllipticCurves.pdf + +Jun 7, 2012 timleslie uploaded pygeom to github on + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..139597f --- /dev/null +++ b/LICENSE @@ -0,0 +1,2 @@ + + diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..139597f --- /dev/null +++ b/NOTICE @@ -0,0 +1,2 @@ + + diff --git a/README b/README new file mode 100644 index 0000000..982b208 --- /dev/null +++ b/README @@ -0,0 +1,5 @@ +pygeom a Python package for performing calculations in planar universal geometry + + + + diff --git a/REFERENCE/112BookReviews.pdf b/REFERENCE/112BookReviews.pdf new file mode 100644 index 0000000..2148ba3 Binary files /dev/null and b/REFERENCE/112BookReviews.pdf differ diff --git a/REFERENCE/Affine_and_Projective_Universal_Geometry.pdf b/REFERENCE/Affine_and_Projective_Universal_Geometry.pdf new file mode 100644 index 0000000..483c361 Binary files /dev/null and b/REFERENCE/Affine_and_Projective_Universal_Geometry.pdf differ diff --git a/REFERENCE/Book-Review-Divine-Proportions-Rational-Trigonometry-to-Universal-Geometry.pdf b/REFERENCE/Book-Review-Divine-Proportions-Rational-Trigonometry-to-Universal-Geometry.pdf new file mode 100644 index 0000000..e0c09fe Binary files /dev/null and b/REFERENCE/Book-Review-Divine-Proportions-Rational-Trigonometry-to-Universal-Geometry.pdf differ diff --git a/REFERENCE/EllipticCurveHandbook.pdf b/REFERENCE/EllipticCurveHandbook.pdf new file mode 100644 index 0000000..74af9cc Binary files /dev/null and b/REFERENCE/EllipticCurveHandbook.pdf differ diff --git a/REFERENCE/NeubergCubic-K001.pdf b/REFERENCE/NeubergCubic-K001.pdf new file mode 100644 index 0000000..7241141 Binary files /dev/null and b/REFERENCE/NeubergCubic-K001.pdf differ diff --git a/REFERENCE/NeubergEuler.pdf b/REFERENCE/NeubergEuler.pdf new file mode 100644 index 0000000..0e4808d Binary files /dev/null and b/REFERENCE/NeubergEuler.pdf differ diff --git a/REFERENCE/Neuberg_cubics_over_finite_fields.pdf b/REFERENCE/Neuberg_cubics_over_finite_fields.pdf new file mode 100644 index 0000000..f8a77c2 Binary files /dev/null and b/REFERENCE/Neuberg_cubics_over_finite_fields.pdf differ diff --git a/REFERENCE/PlanarUniversalGeometry.pdf b/REFERENCE/PlanarUniversalGeometry.pdf new file mode 100644 index 0000000..681bec9 Binary files /dev/null and b/REFERENCE/PlanarUniversalGeometry.pdf differ diff --git a/REFERENCE/Rational-Trigonometry-Applied-to-Robotics.pdf b/REFERENCE/Rational-Trigonometry-Applied-to-Robotics.pdf new file mode 100644 index 0000000..5b058b7 Binary files /dev/null and b/REFERENCE/Rational-Trigonometry-Applied-to-Robotics.pdf differ diff --git a/REFERENCE/Rice-2013.pdf b/REFERENCE/Rice-2013.pdf new file mode 100644 index 0000000..9bb2286 Binary files /dev/null and b/REFERENCE/Rice-2013.pdf differ diff --git a/REFERENCE/The_number_of_occurrences_of_a_fixed_spread_among_n_directions_in_vector_spaces_over_finite_fields.pdf b/REFERENCE/The_number_of_occurrences_of_a_fixed_spread_among_n_directions_in_vector_spaces_over_finite_fields.pdf new file mode 100644 index 0000000..3db1840 Binary files /dev/null and b/REFERENCE/The_number_of_occurrences_of_a_fixed_spread_among_n_directions_in_vector_spaces_over_finite_fields.pdf differ diff --git "a/REFERENCE/Trigonometry- The study of\342\200\246 circles? | timl.blog.pdf" "b/REFERENCE/Trigonometry- The study of\342\200\246 circles? | timl.blog.pdf" new file mode 100644 index 0000000..a73ad6f Binary files /dev/null and "b/REFERENCE/Trigonometry- The study of\342\200\246 circles? | timl.blog.pdf" differ diff --git a/REFERENCE/Trigonometry-The-Study-Of-Circles.pdf b/REFERENCE/Trigonometry-The-Study-Of-Circles.pdf new file mode 100644 index 0000000..a73ad6f Binary files /dev/null and b/REFERENCE/Trigonometry-The-Study-Of-Circles.pdf differ diff --git a/REFERENCE/Universal-Hyperbolic-Geometry-I-Trigonometry.pdf b/REFERENCE/Universal-Hyperbolic-Geometry-I-Trigonometry.pdf new file mode 100644 index 0000000..d2026ec Binary files /dev/null and b/REFERENCE/Universal-Hyperbolic-Geometry-I-Trigonometry.pdf differ diff --git a/REFERENCE/Universal-Hyperbolic-Geometry-II-A-pictorial-overview.pdf b/REFERENCE/Universal-Hyperbolic-Geometry-II-A-pictorial-overview.pdf new file mode 100644 index 0000000..a682e4f Binary files /dev/null and b/REFERENCE/Universal-Hyperbolic-Geometry-II-A-pictorial-overview.pdf differ diff --git a/REFERENCE/Universal-Hyperbolic-Geometry-Summary-of-NJWildbergers-online-lecture-series.pdf b/REFERENCE/Universal-Hyperbolic-Geometry-Summary-of-NJWildbergers-online-lecture-series.pdf new file mode 100644 index 0000000..e7096d9 Binary files /dev/null and b/REFERENCE/Universal-Hyperbolic-Geometry-Summary-of-NJWildbergers-online-lecture-series.pdf differ diff --git a/REFERENCE/WhyEllipsesAreNotEllipticCurves.pdf b/REFERENCE/WhyEllipsesAreNotEllipticCurves.pdf new file mode 100644 index 0000000..9bb2286 Binary files /dev/null and b/REFERENCE/WhyEllipsesAreNotEllipticCurves.pdf differ diff --git a/REFERENCE/artingeogebra.pdf b/REFERENCE/artingeogebra.pdf new file mode 100644 index 0000000..9389409 Binary files /dev/null and b/REFERENCE/artingeogebra.pdf differ diff --git a/REFERENCE/equalchords.pdf b/REFERENCE/equalchords.pdf new file mode 100644 index 0000000..9cd0420 Binary files /dev/null and b/REFERENCE/equalchords.pdf differ diff --git a/REFERENCE/hyperbolic-geo.pdf b/REFERENCE/hyperbolic-geo.pdf new file mode 100644 index 0000000..e7096d9 Binary files /dev/null and b/REFERENCE/hyperbolic-geo.pdf differ diff --git a/REFERENCE/integral_over_finite_fields.pdf b/REFERENCE/integral_over_finite_fields.pdf new file mode 100644 index 0000000..42c8650 Binary files /dev/null and b/REFERENCE/integral_over_finite_fields.pdf differ diff --git a/REFERENCE/neubergs.pdf b/REFERENCE/neubergs.pdf new file mode 100644 index 0000000..7bbdadc Binary files /dev/null and b/REFERENCE/neubergs.pdf differ diff --git a/REFERENCE/report.pdf b/REFERENCE/report.pdf new file mode 100644 index 0000000..681bec9 Binary files /dev/null and b/REFERENCE/report.pdf differ diff --git a/build/lib/pygeom/__init__.py b/build/lib/pygeom/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/build/lib/pygeom/core.py b/build/lib/pygeom/core.py new file mode 100644 index 0000000..2227af7 --- /dev/null +++ b/build/lib/pygeom/core.py @@ -0,0 +1,411 @@ +""" +This module provides the core objects in the pygeom library, namely Points, +Lines and Conics +""" + +from pygeom.util import check_geometry, all_equal + +class Core(object): + """ + Base class to provide an interface and perform some common checks on + the core objects. + """ + def __init__(self, geometry): + self.geometry = geometry + if geometry is None: + geom_form = [] + else: + geom_form = list(geometry.form) + form = list(self.form()) + geom_form + if not all_equal([type(number) for number in form]): + raise TypeError + + def form(self): + """ + Return a tuple representation of the object. + """ + raise NotImplementedError + + def eval(self, x, y): + """ + Evaluate whether the given x, y coordinates "match this object". + """ + raise NotImplementedError + + def __eq__(self, other): + """ + For two objects to be equal they must have the same form + and also reside in the same geometry. + """ + return bool(self.__class__ == other.__class__ and + self.form() == other.form() and + self.geometry == other.geometry) + + def __ne__(self, other): + return not self == other + +class Point(Core): + """ + A point is defined as pair of values, [x, y] taken from a particular field. + A point exists within the context of a geometry over the same field. + + Points can also be used to represent vectors, and are used interchangably + in this implementation, despite their subtle semantic differences. + """ + + def __init__(self, x, y, geometry=None): + """ + Create a point [x, y] in the given geometry. + + If no geometry is specified then none of the metric functionality of + the library will be available for this point. + """ + self.x = x + self.y = y + Core.__init__(self, geometry) + + def form(self): + """ + Return a tuple representation of the object. + """ + return self.x, self.y + + def eval(self, x, y): + """ + Evaluate whether the given x, y coordinates "match this object". + + In this case, check if they are equal to the point. + """ + if x == self.x and y == self.y: + return 0 + else: + return 1 + + def __repr__(self): + return "[%s, %s]" % (str(self.x), str(self.y)) + + def __sub__(self, other): + """ + Vector substraction. + """ + return Point(self.x - other.x, self.y - other.y, self.geometry) + + def __mul__(self, other): + """ + Scalar multiplcation. + """ + return Point(self.x * other, self.y * other, self.geometry) + + def __rmul__(self, other): + """ + Scalar multiplcation. + """ + return self * other + + def __add__(self, other): + """ + Vector addition. + """ + return Point(self.x + other.x, self.y + other.y, self.geometry) + + def __div__(self, other): + """ + Scalar division. + """ + return Point(self.x / other, self.y / other, self.geometry) + + @check_geometry + def null(self): + """ + Boolean method to check if this is a null point. + + A null point is one whose quadrance from the origin is zero. + """ + return self.norm() == 0 + + @check_geometry + def norm(self): + """ + The norm of the vector from the origin to this point. + """ + return self.geometry.norm(self) + + def circle(self, quadrance): + """ + Create a circle with a given quadrance centred at this point. + """ + x, y = self.form() + a, b, c = self.geometry.form + return Conic(a, 2*b, c, -2*(a*x + b*y), -2*(b*x + c*y), + self.norm() - quadrance, self.geometry) + + +class Line(Core): + + def __init__(self, a, b, c, geometry=None): + a, b, c = a.reduce([b, c]) + self.a = a + self.b = b + self.c = c + Core.__init__(self, geometry) + + def form(self): + """ + Return a tuple representation of the object. + """ + return self.a, self.b, self.c + + def eval(self, x, y): + """ + Evaluate whether the given x, y coordinates "match this object". + + In this case check whether the point is on the line. + """ + return self.a*x + self.b*y + self.c + + def __repr__(self): + return "<%s:%s:%s>" % (str(self.a), str(self.b), str(self.c)) + + + def vector(self): + """ + Return a Point which represents a vector parallel to this line. + """ + return Point(-self.b, self.a, self.geometry) + + @check_geometry + def null(self): + """ + Boolean method to check if this is a null line. + + A line is a null line of all points on it are null points. + """ + return self.vector().null() + + +class Conic(Core): + def __init__(self, a, b, c, d, e, f, geometry=None): + #pylint: disable-msg=R0913 + self.a = a + self.b = b + self.c = c + self.d = d + self.e = e + self.f = f + Core.__init__(self, geometry) + + def form(self): + """ + Return a tuple representation of the object. + """ + return self.a, self.b, self.c, self.d, self.e, self.f + + def __repr__(self): + return "<%s:%s:%s:%s:%s:%s>" % (str(self.a), str(self.b), str(self.c), + str(self.d), str(self.e), str(self.f)) + + def eval(self, x, y): + """ + Evaluate whether the given x, y coordinates "match this object". + + In this case check whether the point is on the conic. + """ + a, b, c, d, e, f = self.form() + return a*x*x + b*x*y + c*y*y + d*x + e*y + f + + def through(self, point): + """ + Check whether the conic passes through the point. + """ + x, y = point.form() + return self.eval(x, y) == 0 + + def det(self): + """ + The determinant of the matrix P [[a, b/2], [b/2, c]]. + """ + return self.a*self.c - self.b*self.b/4 + + def _point_on(self): + a, b, c, d, e, f = self.form() + #y = (-(b + e) + ((b + e)*(b + e) - 4*c*(a + d + f)).sqrt())/(2*c) + y = (-e + (e*e - 4*c*f).sqrt())/(2*c) + x = y - y + point = Point(x, y, self.geometry) + assert self.through(point) + return point + + def is_parabola(self): + """ + Check whether this conic is a parabola. + """ + return self.det() == 0 + + @check_geometry + def is_circle(self): + """ + Boolean function to determine whether this conic is a circle. + """ + a, b, c = self.geometry.form + a1, b1, c1, _, _, _ = self.form() + + return (a1*2*b == b1*a and + a1*c == c1*a and + b1*c == c1*2*b) + + @check_geometry + def centre_quadrance(self): + """ + Return a point and a quadrance, representing the centre and radius + quadrance of the circle. + """ + # return a point and a quadrance + a, b, c = self.geometry.form + d1, e1 = self.d, self.e + + x0 = -(c*d1 - b*e1)/(2*self.geometry.det()) + y0 = -(-b*d1 + a*e1)/(2*self.geometry.det()) + + centre = Point(x0, y0, self.geometry) + + K = centre.norm() - self.f + + return centre, K + + @check_geometry + def focus_directrix(self): + """ + Calculate the two focus/directrix pairs for this conic as well as + the corresponding ratio K. + """ + #pylint: disable-msg=R0914 + from pygeom.pairs import PointLine + a, b, c = self.geometry.form + D, E, F = self.d, self.e, self.f + a1 = a - self.a + b1 = b - self.b/2 + + AA = 4*(a*b1*b1 - 2*b*a1*b1 + c*a1*a1 - a1*self.geometry.det()) + BB = 4*a1*((a*E - b*D)*b1 + (- b*E + c*D)*a1) + CC = a1*a1*(a*E*E - 2*b*E*D + c*D*D - 4*self.geometry.det()*F) + + c11 = (-BB + (BB*BB - 4*AA*CC).sqrt())/(2*AA) + c12 = (-BB - (BB*BB - 4*AA*CC).sqrt())/(2*AA) + + direc1, direc2 = (Line(a1, b1, c11, self.geometry), + Line(a1, b1, c12, self.geometry)) + + K = (a*b1*b1 - 2*b*a1*b1 + c*a1*a1)/(a1*self.geometry.det()) + + x1 = -(c*(2*c11 + D) - b*(2*c11*b1/a1 + E))/(2*self.geometry.det()) + y1 = -(-b*(2*c11 + D) + a*(2*c11*b1/a1 + E))/(2*self.geometry.det()) + + x2 = -(c*(2*c12 + D) - b*(2*c12*b1/a1 + E))/(2*self.geometry.det()) + y2 = -(-b*(2*c12 + D) + a*(2*c12*b1/a1 + E))/(2*self.geometry.det()) + + focus1 = Point(x1, y1, self.geometry) + focus2 = Point(x2, y2, self.geometry) + + focus_direc_1 = PointLine(focus1, direc1) + focus_direc_2 = PointLine(focus2, direc2) + + return (focus_direc_1, focus_direc_2, K) + + + @check_geometry + def co_diagonal(self, line): + """ + If this conic is a grammola, then return + the co-diagonal line as well as the grammola constant K. + """ + + A, B, C, D, E, F = self.form() + a1, b1, _ = line.form() + a, b, c = self.geometry.form + + alpha = (A*c - B*b + C*a) + d1 = line.vector().norm() + assert d1 == a*b1*b1 - 2*b*a1*b1 + c*a1*a1 + + a2 = ((2*A*d1 - a1*a1*alpha)/(2*d1*d1)).sqrt() + b22 = ((2*C*d1 - b1*b1*alpha)/(2*d1*d1)).sqrt() + if a2 == 0: + b2 = a2 + 1 + else: + b2 = (( B*d1 - a1*b1*alpha)/(2*d1*d1))/a2 + print b2, b22, -b22 + + x = 2*A*d1 - alpha*a1*a1 + y = B*d1 - alpha*a1*b1 + z = 2*C*d1 - alpha*b1*b1 + assert x*z == y*y + + d2 = a*b2*b2 - 2*b*a2*b2 + c*a2*a2 + assert a1*b2 - a2*b1 != 0 + + c1 = ( b2*D - a2*E)/(2*d2*(a1*b2 - a2*b1)) + c2 = (-b1*D + a1*E)/(2*d1*(a1*b2 - a2*b1)) + + assert c1 == line.c + + K = (a*c - b*b)*(c1*c1/d1 + c2*c2/d2 - F/(d1*d2)) + + return Line(a2, b2, c2, self.geometry), K + + + def tangent(self, point): + """ + Calculate the tangent to the conic through the given point. + + If the point does not lie on the conic a ValueError is raised. + """ + if not self.through(point): + raise ValueError + return self.polar(point) + + def is_tangent(self, line): + """ + Check if the given line is tangent to this conic. + """ + # (Bc + Db + Ea)^2 -4(ACc^2 + AFb^2 + CFa^2) + 4((AE - BD)bc + (CD - BE)ac + (BF- DE)ab) = 0 + + A, B, C, D, E, F = self.form() + a, b, c = line.form() + + return (B*c + D*b + E*a)*(B*c + D*b + E*a) - 4*(A*C*c*c + A*F*b*b + C*F*a*a) + 4*((A*E - B*D)*b*c + (C*D - B*E)*a*c + (B*F - D*E)*a*b ) == 0 + + + def pole(self, polar): + """ + Calculate the pole of the given polar. + """ + #pylint: disable-msg=R0914 + a, b, c, d, e, f = self.form() + det_p = self.det() + a1, b1, c1 = polar.form() + + num = (d*(c*d - b*e/2) + e*(-b*d/2 + a*e ))/(2*det_p) - 2*f + den = (d*(c*a1 - b*b1/2) + e*(-b*a1/2 + a*b1))/(2*det_p) - c1 + + a2 = num*a1/den - d + b2 = num*b1/den - e + + x = 1/(2*det_p)*(c*a2 - b*b2/2) + y = 1/(2*det_p)*(-b*a2/2 + a*b2) + + return Point(x, y, self.geometry) + + def polar(self, pole): + """ + Calculate the polar of the given pole. + """ + x, y = pole.form() + a, b, c, d, e, f = self.form() + + # (2PX_0 + q)X + (qX_0 + 2r) + + a1 = (2*(a*x + b*y/2) + d) + b1 = (2*(b*x/2 + c*y) + e) + + c1 = d*x + e*y + 2*f + return Line(a1, b1, c1, self.geometry) diff --git a/build/lib/pygeom/field.py b/build/lib/pygeom/field.py new file mode 100644 index 0000000..1d16147 --- /dev/null +++ b/build/lib/pygeom/field.py @@ -0,0 +1,383 @@ +""" +This module contains classes which implement various different fields. + +Recall that a mathematical field is a set of "numbers" which are closed under +the four basic operations of addition, subtraction, multiplication and division. + +All calculations performed by pygeom are done over a specific field and thus +this is very core of the package. +""" + +import random + +from pygeom.util import inverse, gcd, isqrt, is_square, shanks_tonelli + +class Field(object): + """ + This base class provides the interface for numbers within a given field. + + All field classes must implement the full interface defined here to be able + to be used by pygeom. + """ + + def __init__(self, value, *args, **kwargs): + pass + + def __add__(self, other): + raise NotImplementedError + + def __sub__(self, other): + raise NotImplementedError + + def __mul__(self, other): + raise NotImplementedError + + def __neg__(self): + raise NotImplementedError + + def __div__(self, other): + raise NotImplementedError + + def __radd__(self, other): + raise NotImplementedError + + def __rsub__(self, other): + raise NotImplementedError + + def __rmul__(self, other): + raise NotImplementedError + + def __rdiv__(self, other): + raise NotImplementedError + + def __eq__(self, other): + raise NotImplementedError + + def __ne__(self, other): + return not bool(self == other) + + def is_square(self): + """ + Boolean function to check if the number is a square in the field. + + E.g. for a given :math:`x \in F`, does there exist an :math:`a \in F` such that :math:`a^2 = x`. + + :rtype: Boolean + """ + raise NotImplementedError + + def sqrt(self): + """ + The square root of the number in the field. + + Returns the value :math:`a \in F` such that :math:`a^2 = x`. + + :raises: ValueError if no such :math:`a` exists. + """ + raise NotImplementedError + + def reduce(self, others): + """ + Reduce this number, along with a list of others so that all common + factors are removed. + """ + raise NotImplementedError + + @classmethod + def random(cls): + raise NotImplementedError + +class FiniteField(Field): + + base = 3 + + def __init__(self, value, base=None): + Field.__init__(self, value) + + # We're actually pedantic about types here. + if type(value) not in [int, long]: + raise TypeError + if base is None: + self._base = self.base + elif type(base) not in [int, long]: + raise TypeError, "base must be a prime number (%s)" % str(base) + elif base <= 1: + raise ValueError, "base must be a prime number (%s)" % str(base) + else: + self._base = base + + # Convert to a value between [0, base-1] + self.value = value % self._base + + def __repr__(self): + return "%d (%d)" % (self.value, self._base) + + def _op(self, op, other): + """ + Perform an operator on this and another object. + """ + if other.__class__ == self.__class__: + return self.__class__(op(other.value), self._base) + elif type(other) in [int, long]: + return self.__class__(op(other), self._base) + else: + raise TypeError + + def __add__(self, other): + return self._op(self.value.__add__, other) + + def __sub__(self, other): + return self._op(self.value.__sub__, other) + + def __mul__(self, other): + try: + return self._op(self.value.__mul__, other) + except TypeError: + try: + return other.__rmul__(self) + except: + raise TypeError + + def __neg__(self): + return self.__class__(0, self._base) - self + + def __div__(self, other): + if other.__class__ == self.__class__: + return self * inverse(other.value, self._base) + elif type(other) in [int, long]: + return self * inverse(other, self._base) + else: + raise TypeError + + def __radd__(self, other): + return self._op(self.value.__add__, other) + + def __rsub__(self, other): + return self._op((-self.value).__add__, other) + + def __rmul__(self, other): + return self._op(self.value.__mul__, other) + + def __rdiv__(self, other): + return self.__class__(other * inverse(self.value, self._base), + self._base) + + def __eq__(self, other): + if type(other) in [int, long]: + other = self.__class__(other, self._base) + + if other.__class__ == self.__class__: + return self.value == other.value and self._base == other._base + else: + raise TypeError, "Equality not defined for (%s)" % str(other) + + def is_square(self): + """ + Boolean function to check if the number is a square in the field. + + E.g. for a given x \in F, does there exist an a \in F such that a*a = x. + + If x is a square then x^(p - 1)/2 = 1 (mod p). + + :rtype: Boolean + """ + result = 1 + for _ in range((self._base - 1)/2): + result *= self.value + return result % self._base == 1 or self.value == 0 + + def sqrt(self): + """ + The square root of the number in the field. + + Returns the value a \in F such that a*a = x. + + If no such a exists, raises ValueError. + """ + if not self.is_square(): + raise ValueError, "This number is not a square! (%s)" % str(self) + a = self.__class__(shanks_tonelli(self.value, self._base)) + assert a*a == self + return a + + def reduce(self, others): + """ + Reduce this number, along with a list of others so that all common + factors are removed. + """ + if self == 0: + if others: + return [self] + others[0].reduce(others[1:]) + else: + return [self] + else: + return [self/self] + [x/self for x in others] + + @classmethod + def random(cls): + """ + Return a random field object. + """ + return cls(random.randint(0, cls.base - 1)) + +class Rational(Field): + + _min_random = -10 + _max_random = 10 + + def __init__(self, num, den=1): + Field.__init__(self, (num, den)) + self.num = num + self.den = den + if self.den == 0: + raise ValueError, "Denominator in rational cannot be zero" + if type(self.num) not in [int, long]: + raise TypeError, "Numerator must be an integer (%s)" % str(self.num) + if type(self.den) not in [int, long]: + raise TypeError, \ + "Denominator must be an integer (%s)" % str(self.den) + self._reduce() + + def __repr__(self): + return "%d/%d" % (self.num, self.den) + + def _reduce(self): + """ + Reduce the values to remove any common factors. + """ + gcd_ = gcd(self.num, self.den) + self.num /= gcd_ + self.den /= gcd_ + + def _get_num_den(self, other): + """ + Return a (numerator, denominator) pair for the given value. Handles + both Rationals and regular integers. Other types will raise a + TypeError + """ + if type(other) in [int, long]: + return other, 1 + elif other.__class__ == self.__class__: + return other.num, other.den + else: + raise TypeError, str(self.__class__) + str(other.__class__) + + def __add__(self, other): + a1, b1 = self.num, self.den + a2, b2 = self._get_num_den(other) + return Rational(a1*b2 + a2*b1, b1*b2) + + def __sub__(self, other): + a1, b1 = self.num, self.den + a2, b2 = self._get_num_den(other) + return Rational(a1*b2 - a2*b1, b1*b2) + + def __mul__(self, other): + a1, b1 = self.num, self.den + try: + a2, b2 = self._get_num_den(other) + except TypeError: + try: + x = other.__rmul__(self) + if x == NotImplemented: + raise NotImplementedError + return x + except: + raise TypeError + return Rational(a1*a2, b1*b2) + + def __neg__(self): + a1, b1 = self.num, self.den + return Rational(-a1, b1) + + def __div__(self, other): + a1, b1 = self.num, self.den + a2, b2 = self._get_num_den(other) + if b1*a2 == 0: + raise ZeroDivisionError + return Rational(a1*b2, b1*a2) + + def __radd__(self, other): + return self + other + + def __rsub__(self, other): + return (-self) + other + + def __rmul__(self, other): + return self * other + + def __rdiv__(self, other): + a1, b1 = self.num, self.den + if a1 == 0: + raise ZeroDivisionError + return other * Rational(b1, a1) + + def __eq__(self, other): + if type(other) in [int, long]: + return self.num == other and self.den == 1 + elif other.__class__ == self.__class__: + return other.num == self.num and other.den == self.den + else: + raise TypeError, "Equality not defined for (%s)" % str(other) + + def is_square(self): + """ + Boolean function to check if the number is a square in the field. + + E.g. for a given x \in F, does there exist an a \in F such that a*a = x. + """ + return is_square(self.num) and is_square(self.den) + + def sqrt(self): + """ + The square root of the number in the field. + + Returns the value a \in F such that a*a = x. + + If no such a exists, raises ValueError. + """ + if self.is_square(): + return Rational(isqrt(self.num), isqrt(self.den)) + else: + raise ValueError, "%s is not a square" % str(self) + + def reduce(self, others): + """ + Reduce this number, along with a list of others so that all common + factors are removed. + """ + if self == 0: + if others: + return [self] + others[0].reduce(others[1:]) + else: + return [self] + + common_denom = self.den + for x in others: + common_denom *= x.den + + + self = self*common_denom + others = [x*common_denom for x in others] + + gcd_ = self.num + for x in others: + gcd_ = gcd(gcd_, x.num) + + self = self.__div__(gcd_) + others = [x/gcd_ for x in others] + return [self] + others + + + @classmethod + def random(cls): + """ + Return a random field object. + """ + num = random.randint(cls._min_random, cls._max_random) + den = random.randint(cls._min_random, cls._max_random) + if den == 0: + den = 1 + return cls(num, den) + + diff --git a/build/lib/pygeom/fourier.py b/build/lib/pygeom/fourier.py new file mode 100644 index 0000000..2496eb9 --- /dev/null +++ b/build/lib/pygeom/fourier.py @@ -0,0 +1,217 @@ +import numpy as np +import wx + +import matplotlib +matplotlib.interactive(False) +matplotlib.use('WXAgg') +from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg +from matplotlib.figure import Figure +from matplotlib.pyplot import gcf, setp + + +class Knob: + """ + Knob - simple class with a "setKnob" method. + A Knob instance is attached to a Param instance, e.g. param.attach(knob) + Base class is for documentation purposes. + """ + def setKnob(self, value): + pass + + +class Param: + """ + The idea of the "Param" class is that some parameter in the GUI may have + several knobs that both control it and reflect the parameter's state, e.g. + a slider, text, and dragging can all change the value of the frequency in + the waveform of this example. + The class allows a cleaner way to update/"feedback" to the other knobs when + one is being changed. Also, this class handles min/max constraints for all + the knobs. + Idea - knob list - in "set" method, knob object is passed as well + - the other knobs in the knob list have a "set" method which gets + called for the others. + """ + def __init__(self, initialValue=None, minimum=0., maximum=1.): + self.minimum = minimum + self.maximum = maximum + if initialValue != self.constrain(initialValue): + raise ValueError('illegal initial value') + self.value = initialValue + self.knobs = [] + + def attach(self, knob): + self.knobs += [knob] + + def set(self, value, knob=None): + self.value = value + self.value = self.constrain(value) + for feedbackKnob in self.knobs: + if feedbackKnob != knob: + feedbackKnob.setKnob(self.value) + return self.value + + def constrain(self, value): + if value <= self.minimum: + value = self.minimum + if value >= self.maximum: + value = self.maximum + return value + + +class SliderGroup(Knob): + def __init__(self, parent, label, param): + self.sliderLabel = wx.StaticText(parent, label=label) + self.sliderText = wx.TextCtrl(parent, -1, style=wx.TE_PROCESS_ENTER) + self.slider = wx.Slider(parent, -1) + self.slider.SetMax(param.maximum*1000) + self.setKnob(param.value) + + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(self.sliderLabel, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=2) + sizer.Add(self.sliderText, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=2) + sizer.Add(self.slider, 1, wx.EXPAND) + self.sizer = sizer + + self.slider.Bind(wx.EVT_SLIDER, self.sliderHandler) + self.sliderText.Bind(wx.EVT_TEXT_ENTE, self.sliderTextHandler) + + self.param = param + self.param.attach(self) + + def sliderHandler(self, evt): + value = evt.GetInt() / 1000. + self.param.set(value) + + def sliderTextHandler(self, evt): + value = float(self.sliderText.GetValue()) + self.param.set(value) + + def setKnob(self, value): + self.sliderText.SetValue('%g'%value) + self.slider.SetValue(value*1000) + + +class FourierDemoFrame(wx.Frame): + def __init__(self, *args, **kwargs): + wx.Frame.__init__(self, *args, **kwargs) + + self.fourierDemoWindow = FourierDemoWindow(self) + self.frequencySliderGroup = SliderGroup(self, label='Frequency f0:', \ + param=self.fourierDemoWindow.f0) + self.amplitudeSliderGroup = SliderGroup(self, label=' Amplitude a:', \ + param=self.fourierDemoWindow.A) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.fourierDemoWindow, 1, wx.EXPAND) + sizer.Add(self.frequencySliderGroup.sizer, 0, \ + wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5) + sizer.Add(self.amplitudeSliderGroup.sizer, 0, \ + wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, border=5) + self.SetSizer(sizer) + +class FourierDemoWindow(wx.Window, Knob): + def __init__(self, *args, **kwargs): + wx.Window.__init__(self, *args, **kwargs) + self.lines = [] + self.figure = Figure() + self.canvas = FigureCanvasWxAgg(self, -1, self.figure) + self.canvas.callbacks.connect('button_press_event', self.mouseDown) + self.canvas.callbacks.connect('motion_notify_event', self.mouseMotion) + self.canvas.callbacks.connect('button_release_event', self.mouseUp) + self.state = '' + self.mouseInfo = (None, None, None, None) + self.f0 = Param(2., minimum=0., maximum=6.) + self.A = Param(1., minimum=0.01, maximum=2.) + self.draw() + + # Not sure I like having two params attached to the same Knob, + # but that is what we have here... it works but feels kludgy - + # although maybe it's not too bad since the knob changes both params + # at the same time (both f0 and A are affected during a drag) + self.f0.attach(self) + self.A.attach(self) + self.Bind(wx.EVT_SIZE, self.sizeHandler) + + def sizeHandler(self, *args, **kwargs): + self.canvas.SetSize(self.GetSize()) + + def mouseDown(self, evt): + if self.lines[0] in self.figure.hitlist(evt): + self.state = 'frequency' + elif self.lines[1] in self.figure.hitlist(evt): + self.state = 'time' + else: + self.state = '' + self.mouseInfo = (evt.xdata, evt.ydata, max(self.f0.value, .1), self.A.value) + + def mouseMotion(self, evt): + if self.state == '': + return + x, y = evt.xdata, evt.ydata + if x is None: # outside the axes + return + x0, y0, f0Init, AInit = self.mouseInfo + self.A.set(AInit+(AInit*(y-y0)/y0), self) + if self.state == 'frequency': + self.f0.set(f0Init+(f0Init*(x-x0)/x0)) + elif self.state == 'time': + if (x-x0)/x0 != -1.: + self.f0.set(1./(1./f0Init+(1./f0Init*(x-x0)/x0))) + + def mouseUp(self, evt): + self.state = '' + + def draw(self): + if not hasattr(self, 'subplot1'): + self.subplot1 = self.figure.add_subplot(211) + self.subplot2 = self.figure.add_subplot(212) + x1, y1, x2, y2 = self.compute(self.f0.value, self.A.value) + color = (1., 0., 0.) + self.lines += self.subplot1.plot(x1, y1, color=color, linewidth=2) + self.lines += self.subplot2.plot(x2, y2, color=color, linewidth=2) + #Set some plot attributes + self.subplot1.set_title("Click and drag waveforms to change frequency and amplitude", fontsize=12) + self.subplot1.set_ylabel("Frequency Domain Waveform X(f)", fontsize = 8) + self.subplot1.set_xlabel("frequency f", fontsize = 8) + self.subplot2.set_ylabel("Time Domain Waveform x(t)", fontsize = 8) + self.subplot2.set_xlabel("time t", fontsize = 8) + self.subplot1.set_xlim([-6, 6]) + self.subplot1.set_ylim([0, 1]) + self.subplot2.set_xlim([-2, 2]) + self.subplot2.set_ylim([-2, 2]) + self.subplot1.text(0.05, .95, r'$X(f) = \mathcal{F}\{x(t)\}$', \ + verticalalignment='top', transform = self.subplot1.transAxes) + self.subplot2.text(0.05, .95, r'$x(t) = a \cdot \cos(2\pi f_0 t) e^{-\pi t^2}$', \ + verticalalignment='top', transform = self.subplot2.transAxes) + + def compute(self, f0, A): + f = np.arange(-6., 6., 0.02) + t = np.arange(-2., 2., 0.01) + x = A*np.cos(2*np.pi*f0*t)*np.exp(-np.pi*t**2) + X = A/2*(np.exp(-np.pi*(f-f0)**2) + np.exp(-np.pi*(f+f0)**2)) + return f, X, t, x + + def repaint(self): + self.canvas.draw() + + def setKnob(self, value): + # Note, we ignore value arg here and just go by state of the params + x1, y1, x2, y2 = self.compute(self.f0.value, self.A.value) + setp(self.lines[0], xdata=x1, ydata=y1) + setp(self.lines[1], xdata=x2, ydata=y2) + self.repaint() + + +class App(wx.App): + def OnInit(self): + sys.stdout = stdout + print "yay" + self.frame1 = FourierDemoFrame(parent=None, title="Fourier Demo", size=(640, 480)) + self.frame1.Show() + return True + +import sys +stdout = sys.stdout +app = App() +app.MainLoop() diff --git a/build/lib/pygeom/geometry.py b/build/lib/pygeom/geometry.py new file mode 100644 index 0000000..71783b4 --- /dev/null +++ b/build/lib/pygeom/geometry.py @@ -0,0 +1,52 @@ +# pylint: disable-msg=C0103 + +class Geometry(object): + + def __init__(self, a, b, c): + self.form = a, b, c + if self.det() == 0: + raise ValueError, "Singular matrix cannot be used for a geometry." + + def dot(self, point1, point2): + a, b, c = self.form + x1, y1 = point1.x, point1.y + x2, y2 = point2.x, point2.y + + return x1*(a*x2 + b*y2) + y1*(b*x2 + c*y2) + + def det(self): + a, b, c = self.form + return a*c - b*b + + def norm(self, point): + return self.dot(point, point) + + def __repr__(self): + a, b, c = self.form + return "[%s %s ; %s %s]" % (str(a), str(b), str(b), str(c)) + + def __eq__(self, other): + return bool(self.__class__ == other.__class__ and + self.form == other.form) + + def __ne__(self, other): + return not (self == other) + +def blue(field): + """ + The canonical "blue" geometry. + """ + return Geometry(field(1), field(0), field(1)) + +def green(field): + """ + The canonical "green" geometry. + """ + return Geometry(field(0), field(1), field(0)) + +def red(field): + """ + The canonical "red" geometry. + """ + return Geometry(field(1), field(0), field(-1)) + diff --git a/build/lib/pygeom/pairs.py b/build/lib/pygeom/pairs.py new file mode 100644 index 0000000..aaa16da --- /dev/null +++ b/build/lib/pygeom/pairs.py @@ -0,0 +1,438 @@ +""" +This module contains classes which represent pairs of core objects. +Using pairs of core objects we can then construct further objects. +""" + +from pygeom.core import Point, Line, Conic +from pygeom.util import check_geometry, NullLineError, GeometryError, M + +class LineSegment(object): + """ + A linesegment represents a pair of points. + """ + + def __init__(self, point1, point2): + """ + Create a new line segment from two points. + + Both points must be of the same geometry or else a GeometryError will + be raised. + """ + self.point1 = point1 + self.point2 = point2 + if point1.geometry != point2.geometry: + raise GeometryError + self.geometry = point1.geometry + + x1, y1 = point1.form() + x2, y2 = point2.form() + self.line = Line(y1 - y2, x2 - x1, x1*y2 - x2*y1, self.geometry) + + def __eq__(self, other): + return (self.point1 in [other.point1, other.point2] and + self.point2 in [other.point1, other.point2] and + self.geometry == other.geometry) + + @check_geometry + def midpoint(self): + """ + Return the midpoint M of the two points of the line segments so + that Q(M, point1) == Q(M, point2). + """ + line0 = self.perp_bisector() + + # Find where the equidistant line intersects our line + return Vertex(self.line, line0).point + + @check_geometry + def perp_bisector(self): + """ + Return the perpindicular bisector of the two points. + """ + x1, y1 = self.point1.form() + x2, y2 = self.point2.form() + a, b, c = self.geometry.form + + # Calculate the line of equidistant points + a0 = 2*(a*(x1 - x2) + b*(y1 - y2)) + b0 = 2*(b*(x1 - x2) + c*(y1 - y2)) + c0 = -(a*(x1*x1 - x2*x2) + 2*b*(x1*y1 - x2*y2) + c*(y1*y1 - y2*y2)) + + line0 = Line(a0, b0, c0, self.geometry) + + if self.line.null(): + raise ValueError, \ + "The line between %s and %s is null," \ + "so the midpoint is not defined" % \ + (str(self.point1), str(self.point2)) + return line0 + + @check_geometry + def quadrance(self): + """ + Calculate the quadrance between the two points of the line segment. + """ + return (self.point1 - self.point2).norm() + + @check_geometry + def quadrola(self, K): + x1, y1 = self.point1.form() + x2, y2 = self.point2.form() + a, b, c = self.geometry.form + + X02 = self.point1.norm() + X12 = self.point2.norm() + + aa, bb, cc = M(a*(x2 - x1) + b*(y2 - y1), b*(x2 - x1) + c*(y2 - y1)) + + return Conic(4*(aa - K*a), 4*2*(bb - K*b), 4*(cc - K*c), + 4*(X02 - X12)*(a*(x2 - x1) + b*(y2 - y1)) + \ + 4*K*(a*(x1 + x2) + b*(y1 + y2)), + 4*(X02 - X12)*(b*(x2 - x1) + c*(y2 - y1)) + \ + 4*K*(b*(x1 + x2) + c*(y1 + y2)), + (K - X02 - X12)*(K - X02 - X12) - 4*X02*X12, + self.geometry) + + +class Vertex(object): + """ + A Vertex represents a pair of lines and their point of intersection. + """ + + def __init__(self, line1, line2): + """ + Create a new vertex from two lines. + + Both lines must be of the same geometry or else a GeometryError will + be raised. + """ + self.line1 = line1 + self.line2 = line2 + if line1.geometry != line2.geometry: + raise GeometryError + self.geometry = line1.geometry + + a1, b1, c1 = line1.form() + a2, b2, c2 = line2.form() + den = a1*b2 - a2*b1 + if den == 0: + self.point = None + else: + self.point = Point((b1*c2 - b2*c1)/den, (c1*a2 - c2*a1)/den, + self.geometry) + + def __eq__(self, other): + return (self.line1 in [other.line1, other.line2] and + self.line2 in [other.line1, other.line2] and + self.geometry == other.geometry) + + + def parallel(self): + """ + Boolean function to determine if two lines are parallel. + """ + a1, b1, _ = self.line1.form() + a2, b2, _ = self.line2.form() + return a1*b2 - a2*b1 == 0 + + @check_geometry + def spread(self): + """ + Calculate the spread between two lines, as defined by the forumla + + s = 1 - (U.V)^2/(|U||V|) + """ + vec1 = self.line1.vector() + vec2 = self.line2.vector() + + num = self.geometry.dot(vec1, vec2) + den = vec1.norm() * vec2.norm() + + # If den is zero we must have num zero and the lines must be null so + # the spread is not defined. + if num == den == 0: + raise NullLineError + else: + return 1 - num*num/den + + @check_geometry + def perpendicular(self): + """ + Boolean function to determine if two lines are perpendicular + """ + return self.spread() == 1 + + + @check_geometry + def bisect(self): + """ + Calculate the bisectors of the vertex. This returns a new + vertex, since there are two lines which satisfy the bisection + property. + """ + X = self.point + V = self.line1.vector() + U = self.line2.vector() + + mu = (U.norm()/V.norm()).sqrt() + + X1 = X + V*mu + U + X2 = X - V*mu + U + + assert (V*mu).norm() == U.norm() + + assert PointLine(X + V*mu, self.line1).on() + assert PointLine(X - V*mu, self.line1).on() + + l1 = LineSegment(X, X1).line + l2 = LineSegment(X, X2).line + + spread = Vertex(l1, self.line1).spread() + assert self.spread() == 4*spread*(1 - spread) + + return Vertex(l1, l2) + + @check_geometry + def grammola(self, K): + #pylint: disable-msg=R0914 + a1, b1, c1 = self.line1.form() + a2, b2, c2 = self.line2.form() + a, b, c = self.geometry.form + + d1 = self.line1.vector().norm() + d2 = self.line2.vector().norm() + + conic = Conic(d1*a2*a2 + d2*a1*a1, 2*(d1*a2*b2 + d2*a1*b1), + d1*b2*b2 + d2*b1*b1, + 2*(d2*c1*a1 + d1*c2*a2), 2*(d2*c1*b1 + d1*c2*b2), + c1*c1*d2 + c2*c2*d1 - K*d1*d2/self.geometry.det(), + self.geometry) + A, B, C = conic.a, conic.b, conic.c + assert a*C - b*B + c*A == 2*d1*d2 + return conic + + +class PointLine(object): + + def __init__(self, point, line): + """ + Create a new PointLine from a point and a line. + + The point and line must be of the same geometry or else a GeometryError + will be raised. + """ + self.point = point + self.line = line + if line.geometry != point.geometry: + raise GeometryError + self.geometry = self.point.geometry + + def __eq__(self, other): + return (self.point == other.point and + self.line == other.line and + self.geometry == other.geometry) + + def on(self): + """ + Boolean function to determine whether the point lies on the line. + """ + x, y = self.point.form() + return self.line.eval(x, y) == 0 + + @check_geometry + def reflection(self): + """ + Return the reflection of this point in the given line. + """ + foot = self.altitude().point + return PointLine(foot - (self.point - foot), self.line) + + @check_geometry + def altitude(self): + """ + Construct an altitude from the point to the line. + This is a line which goes through the point and is perpendicular to + the line. + """ + altitude_vertex = self.construct_spread(1) + assert altitude_vertex.line1 == altitude_vertex.line2 + return PointLine(Vertex(self.line, altitude_vertex.line1).point, altitude_vertex.line1) + + @check_geometry + def quadrance(self): + return LineSegment(self.altitude().point, self.point).quadrance() + + def parallel(self): + """ + Construct a new line, parallel to the line and through the point. + """ + a, b, _ = self.line.form() + x, y = self.point.form() + c = -(a*x + b*y) + return Line(a, b, c, self.geometry) + + @check_geometry + def construct_quadrance(self, quadrance): + """ + Calculate the line segment whose points lie on this line + and are a given quadrance from this point. + """ + #pylint: disable-msg=R0914 + + # unpack all the variables + a, b, c, = self.geometry.form + x0, y0 = self.point.form() + a1, b1, c1 = self.line.form() + + if a1 == 0: + # set up the parameters to solve + # alpha * x^2 + beta * x + gamma = 0 + alpha = a*b1*b1 - 2*b*a1*b1 + c*a1*a1 + beta = (2*(a*(a1*c1 + b1*a1*y0) + \ + b*b1*(a1*x0 - b1*y0 - c1) - + c*b1*b1*x0)) + beta = 2*(-a*b1*b1*x0 + b*a1*b1*x0 - b*b1*b1*y0 - b*b1*c1 + + c*a1*b1*y0 + c*a1*c1) + gamma = (a*b1*b1*x0*x0 - b1*b1*quadrance + 2*b*b1*b1*x0*y0 + + 2*b*b1*c1*x0 + c*b1*b1*y0*y0 + c*c1*c1 + 2*c*b1*c1*y0) + if alpha == 0: + # Only one solution, taken from + # solving b*x + g = 0, x = (-g/b, 0) + if beta == 0: + raise ValueError + x1 = x2 = -gamma/beta + else: + # solve for x, y + det = beta*beta - 4*alpha*gamma + + x1 = (-beta + det.sqrt())/(2*alpha) + x2 = (-beta - det.sqrt())/(2*alpha) + + y1 = -(a1*x1 + c1)/b1 + y2 = -(a1*x2 + c1)/b1 + else: + # set up the parameters to solve + # alpha * y^2 + beta * y + gamma = 0 + alpha = a*b1*b1 - 2*b*a1*b1 + c*a1*a1 + beta = (2*(a*(b1*c1 + a1*b1*x0) + \ + b*a1*(b1*y0 - a1*x0 - c1) - + c*a1*a1*y0)) + gamma = (a*(c1 + a1*x0)*(c1 + a1*x0) + 2*b*a1*y0*(a1*x0 + c1) + + a1*a1*(c*y0*y0 - quadrance)) + + if alpha == 0: + # Only one solution, taken from + # solving b*y + g = 0, y = (-g/b, 0) + if beta == 0: + raise ValueError + y1 = y2 = -gamma/beta + else: + # solve for x, y + det = beta*beta - 4*alpha*gamma + + y1 = (-beta + det.sqrt())/(2*alpha) + y2 = (-beta - det.sqrt())/(2*alpha) + + x1 = -(b1*y1 + c1)/a1 + x2 = -(b1*y2 + c1)/a1 + + point1 = Point(x1, y1, self.geometry) + point2 = Point(x2, y2, self.geometry) + + assert PointLine(point1, self.line).on() + assert PointLine(point2, self.line).on() + + assert LineSegment(point1, self.point).quadrance() == quadrance + assert LineSegment(point2, self.point).quadrance() == quadrance + + return LineSegment(point1, point2) + + + @check_geometry + def construct_spread(self, spread): + """ + Calculate the Vertex which meets this point and which creates a given + spread with this line from both of its lines. + """ + #pylint: disable-msg=R0914 + if self.line.null(): + raise NullLineError + + if spread == 0: + par = self.parallel() + return Vertex(par, par) + + a, b, c = self.geometry.form + x0, y0 = self.point.form() + a1, b1, _ = self.line.form() + + U = self.line.vector() + k = (1 - spread)*U.norm() + + # set up the parameters to solve + # alpha * x^2 + beta * x * y + gamma * y^2 = 0 + # if alpha == 0: + # => b * x * y + gamma * y * y == 0 + # y(b * x + gamma * y) == 0 + # x/y == -gamma/beta + alpha = (a*b1 - b*a1)*(a*b1 - b*a1) - k*a + beta = 2*((a*b1 - b*a1)*(b*b1 - c*a1) - b*k) + gamma = (b*b1 - c*a1)*(b*b1 - c*a1) - k*c + + if alpha == 0: + a2 = alpha # = 0; We use alpha like this + b2 = alpha + 1 # = 1; to maintain the field + + a3 = beta + b3 = gamma + else: + det = beta*beta - 4*alpha*gamma + + a2 = a3 = 2*alpha + b2 = beta + det.sqrt() + b3 = beta - det.sqrt() + + c2 = -(a2*x0 + b2*y0) + c3 = -(a3*x0 + b3*y0) + + l2 = Line(a2, b2, c2, self.geometry) + l3 = Line(a3, b3, c3, self.geometry) + + assert PointLine(self.point, l2).on() + assert PointLine(self.point, l3).on() + + assert Vertex(l2, l3).point == self.point or (l2 == l3 and spread == 1) + + assert Vertex(self.line, l2).spread() == spread or l2.null() + assert Vertex(self.line, l3).spread() == spread or l3.null() + + return Vertex(l2, l3) + + @check_geometry + def parabola(self): + """ + Create a parabola using this PointLine as the focus and directrix. + """ + return self.conic(1) + + @check_geometry + def conic(self, K): + """ + Create a conic, using thie PointLine as the focus and directrix, and + having a ratio of K. + """ + if self.line.null(): + raise NullLineError + + a, b, c = self.geometry.form + a1, b1, c1 = self.line.form() + x0, y0, = self.point.form() + + alpha = self.geometry.det()/self.line.vector().norm() + + return Conic(a - K*alpha*a1*a1, 2*(b - K*alpha*a1*b1), + c - K*alpha*b1*b1, + -2*(a*x0 + b*y0 + a1*c1*K*alpha), + -2*(b*x0 + c*y0 + b1*c1*K*alpha), + self.point.norm() - K*alpha*c1*c1, + self.geometry) diff --git a/build/lib/pygeom/plot.py b/build/lib/pygeom/plot.py new file mode 100644 index 0000000..9ca086a --- /dev/null +++ b/build/lib/pygeom/plot.py @@ -0,0 +1,89 @@ +import matplotlib.pyplot as plt +from matplotlib.ticker import IndexLocator, NullFormatter, ScalarFormatter + +from pygeom.geometry import blue, red, green, Geometry + +from field import FiniteField +from core import Line +from conic import Conic + +class Plot(object): + def __init__(self): + self.objects = [] + + def plot(self): + raise NotImplementedError + + def add_object(self, object, name, marker): + self.objects.append((object, name, marker)) + + + +class FinitePlot(Plot): + + def __init__(self): + Plot.__init__(self) + + def plot(self): + fig = plt.figure() + ax = fig.add_subplot(111) + + handles = [] + labels = [] + for object, name, marker in self.objects: + xs = [] + ys = [] + l = object + for x in range(59): + for y in range(59): + if object.eval(x, y) == 0: + xs.append(x) + ys.append(y) + print object, name, marker + print zip(xs, ys) + handles.append(ax.scatter(xs, ys, marker=marker, s=100)) + labels.append(name) + + + ax.set_xlim(-0.5, 10.5) + ax.set_ylim(-0.5, 10.5) + + ax.xaxis.set_major_locator( IndexLocator(-0.5, 1) ) + ax.xaxis.set_minor_locator( IndexLocator(0, 1) ) + ax.yaxis.set_major_locator( IndexLocator(-0.5, 1) ) + ax.yaxis.set_minor_locator( IndexLocator(0, 1) ) + + ax.xaxis.set_major_formatter( NullFormatter() ) + ax.xaxis.set_minor_formatter( ScalarFormatter() ) + ax.yaxis.set_major_formatter( NullFormatter() ) + ax.yaxis.set_minor_formatter( ScalarFormatter() ) + + + ax.set_xticks(range(0, 59), minor=True) + ax.set_yticks(range(0, 59), minor=True) + + ax.set_xticks([x + 0.5 for x in range(0, 59)]) + ax.set_yticks([x + 0.5 for x in range(0, 59)]) + + ax.grid(True) + plt.figlegend(handles, labels, scatterpoints=1, loc=1) + + plt.show() + + +if __name__ == '__main__': + fp = FinitePlot() + + f = FiniteField + f.base = 59 + + l1 = Line(f(1), f(2), f(3)) + l2 = Line(f(1), f(4), f(4)) + c1 = Conic(f(1), f(0), f(-1), f(0), f(0), f(4), blue(f)) + fp.add_object(l1, "foo", "s") + fp.add_object(l2, "bar", "o") + fp.add_object(c1, "baz", "x") + + print "====", c1.centre_quadrance() + + fp.plot() diff --git a/build/lib/pygeom/point.py b/build/lib/pygeom/point.py new file mode 100644 index 0000000..e69de29 diff --git a/build/lib/pygeom/polygon.py b/build/lib/pygeom/polygon.py new file mode 100644 index 0000000..bf938a5 --- /dev/null +++ b/build/lib/pygeom/polygon.py @@ -0,0 +1,32 @@ +class Polygon(object): + + def __init__(self, points): + self.points = points + + + def centroid(self): + pass + + + def altitudes(self): + pass + + def perpindicular_bisectors(self): + pass + + + def angle_bisectors(self): + pass + +# A triangle has: +# 6 midpoints +# 4 centroids +# 6 medians [lines through 2 centroids, vertex, midpoint] +# 4 centrians [ lines through 3 midpoints] + +# Orthocentre becomes the line through (a, a*), (b, b*), (c, c*) + +# We have two midpoints per line, so 2 perpindicular bisectors! +# So we get 4 circumcenters!!! +# Each of these is the centre of a circle which goes through the three points of the triangle... + diff --git a/build/lib/pygeom/util.py b/build/lib/pygeom/util.py new file mode 100644 index 0000000..b349dea --- /dev/null +++ b/build/lib/pygeom/util.py @@ -0,0 +1,167 @@ +def egcd(a, b): + """ + Perform the extended euler algorithm to find, x, y, g such that x*a + y*b = g + """ + # pylint: disable-msg=C0103 + + u, u1 = 1, 0 + v, v1 = 0, 1 + while b: + q = a // b + u, u1 = u1, u - q * u1 + v, v1 = v1, v - q * v1 + a, b = b, a - q * b + return u, v, a + +def gcd(a, b): + """ + Calculate the greatest common divisor of two integers a and b. + """ + return egcd(a, b)[2] + +def inverse(a, p): + """ + Return x such that a*x == 1 (mod p). + """ + if a == 0: + raise ZeroDivisionError + return egcd(a, p)[0] + +def isqrt(n): + """ + Integer square root + + Uses the integer square root algorithm described at: + http://en.wikipedia.org/wiki/Integer_square_root + """ + xn = 1 + xn1 = (xn + n/xn)/2 + while abs(xn1 - xn) > 1: + xn = xn1 + xn1 = (xn + n/xn)/2 + while xn1*xn1 > n: + xn1 -= 1 + return xn1 + +def is_square(n): + """ + Check whether an integer is a square root. + """ + return n >= 0 and isqrt(n)**2 == n + +def shanks_tonelli(n, p): + """ + For a given n solve x^2 = n (mod p), where p is an odd prime and n is a + quadratic residue of p + + Reference: http://planetmath.org/encyclopedia/ShanksTonelliAlgorithm.html + """ + # pylint: disable-msg=C0103 + + if n == 0: + return 0 + + # 1. First find positive integers Q and S such that + # p - 1 = (2^S)*Q, where Q is odd. + + Q = p - 1 + S = 0 + while Q % 2 == 0: + S += 1 + Q /= 2 + + assert Q * 2**S == p - 1 + assert Q % 2 == 1 + + # 2. Then find a quadratic nonresidue W of p and compute V = W^Q(modp) + + W = 2 + while True: + result1 = W**((p-1)/2) % p + result = 1 + for _ in range((p - 1)/2): + result *= W + result %= p + assert result == result1 + if result != 1: + break + W += 1 + + V = 1 + for _ in range(Q): + V *= W + V %= p + + assert V == W**Q % p + + # 3. Then find an integer n' that is the multiplicative inverse of + # n (mod p) (i.e., n'*n = 1 (mod p) ). + nn = inverse(n, p) + + assert (nn * n) % p == 1 + + # 4. Compute R = n^((Q+1/2))(modp) + R = 1 + for _ in range((Q+1)/2): + R *= n + R %= p + assert n**((Q+1)/2) % p == R + + while True: + + # 5. and find the smallest integer i >= 0 that satisfies + # (R^2*n')^(2^i) = 1 (mod p) + i = 0 + RR = R*R*nn % p + while RR != 1: + RR *= RR + RR %= p + i += 1 + + assert (R*R*nn)**(2**i) % p == 1 + + # 6. If i=0, then x=R, and the algorithm stops. + if i == 0: + break + + # 7. Otherwise, compute R' = R*V^2^(S-i-1) (mod p) and repeat the + # procedure for R = R'. + RR = R*(V**(2**(S - i - 1))) % p + assert RR % p == R*(V**(2**(S - i - 1))) % p + R = RR + + assert R*R % p == n % p + return R + +class GeometryError(Exception): pass + +class NullLineError(Exception): pass + +def check_geometry(func): + def _check_geometry(*items): + geometries = [item.geometry for item in items if hasattr(item, "geometry")] + if None in geometries: + i = geometries.index(None) + raise GeometryError, "Object %d (%s) has no geometry." % \ + (i, items[i]) + geom0 = geometries[0] + equal_geoms = [geom == geom0 for geom in geometries] + if False in equal_geoms: + i = equal_geoms.index(False) + raise GeometryError, \ + "Object %d (%s) has a different geometry to the first (%s)" % \ + (i, geometries[i], geom0) + return func(*items) + return _check_geometry + +def M(a, b): + """ + Calculate the symmetric M matrix. + """ + return a*a, a*b, b*b + +def all_equal(objects): + if objects == []: + return True + basis = objects[0] + return False not in [basis == obj for obj in objects] diff --git a/build/lib/pygeom/version.py b/build/lib/pygeom/version.py new file mode 100644 index 0000000..94c5d1d --- /dev/null +++ b/build/lib/pygeom/version.py @@ -0,0 +1 @@ +__version__ = '0.0.1' diff --git a/build/lib/pygeom/wx_demo.py b/build/lib/pygeom/wx_demo.py new file mode 100644 index 0000000..cf26845 --- /dev/null +++ b/build/lib/pygeom/wx_demo.py @@ -0,0 +1,665 @@ +import numpy as np +import wx + +import matplotlib +matplotlib.interactive(False) +matplotlib.use('WXAgg') +from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg +from matplotlib.figure import Figure +from matplotlib.pyplot import gcf, setp + +from matplotlib.ticker import IndexLocator, NullFormatter, ScalarFormatter + +from pygeom.geometry import blue, red, green, Geometry + +from pygeom.field import FiniteField +from pygeom.core import Line, Point +from pygeom.conic import Conic +from pygeom.pairs import PointLine, Vertex, LineSegment + + +class ObjectLine(object): + def __init__(self, parent, panel, object): + self.object = object + self.panel = panel + self.sizer = wx.BoxSizer(wx.HORIZONTAL) + + print type(object[0]) + print type(object[0]) == Line + + if type(object[0]) == Point: + label = "(%d, %d): %s " % (object[0].x.value, object[0].y.value, object[1]) + elif type(object[0]) == Line: + label = "<%d:%d:%d>: %s " % (object[0].a.value, object[0].b.value, object[0].c.value, object[1]) + else: + label = "<%d:%d:%d:%d:%d:%d>: %s " % (object[0].a.value, object[0].b.value, object[0].c.value, + object[0].d.value, object[0].e.value, object[0].f.value, object[1]) + + self.label = wx.StaticText(parent, label=label) + self.edit_button = wx.Button(parent, label="EDIT") + self.del_button = wx.Button(parent, label="DELETE") + self.check = wx.CheckBox(parent) + + self.sizer.Add(self.check, 0, wx.EXPAND) + self.sizer.Add(self.label, 0, wx.EXPAND) + self.sizer.Add(self.edit_button, 0, wx.EXPAND) + self.sizer.Add(self.del_button, 0, wx.EXPAND) + + self.edit_button.Bind(wx.EVT_BUTTON, self.edit_button_handler) + self.del_button.Bind(wx.EVT_BUTTON, self.del_button_handler) + + def edit_button_handler(self, evt): + print "EDIT", self + + def del_button_handler(self, evt): + self.panel.delete_object(self) + self.sizer.Clear(True) + self.panel.sizer.Remove(self.sizer) + self.panel.sizer.Layout() + self.panel.plot.draw() + + +class ObjectPanel(object): + + def __init__(self, parent, plot): + self.parent = parent + self.plot = plot + self.sizer = wx.BoxSizer(wx.VERTICAL) + + self.field = FiniteField + self.field.base = 37 + + self.main_label = wx.StaticText(parent, label="Objects") + self.point_label = wx.StaticText(parent, label="Points") + self.line_label = wx.StaticText(parent, label="Lines") + self.conic_label = wx.StaticText(parent, label="Conics") + + self.points = [] + self.lines = [] + self.conics = [] + + self._arrange_objects() + + def add_point(self, point): + obj_line = ObjectLine(self.parent, self, point) + self.points.append(obj_line) + self.sizer.Insert(1 + len(self.points), obj_line.sizer, 0, wx.EXPAND) + self.sizer.Layout() + self.plot.draw() + + def add_line(self, line): + obj_line = ObjectLine(self.parent, self, line) + self.lines.append(obj_line) + self.sizer.Insert(2 + len(self.points) + len(self.lines), obj_line.sizer, 0, wx.EXPAND) + self.sizer.Layout() + self.plot.draw() + + def add_conic(self, conic): + obj_line = ObjectLine(self.parent, self, conic) + self.conics.append(obj_line) + self.sizer.Insert(3 + len(self.points) + len(self.lines) + len(self.conics), obj_line.sizer, 0, wx.EXPAND) + self.sizer.Layout() + self.plot.draw() + + + def get_objects(self): + return [obj_line.object for obj_line in self.points + self.lines + self.conics] + + def _arrange_objects(self): + self.sizer.Clear() + + self.sizer.Add(self.main_label, 0, wx.EXPAND) + + self.sizer.Add(self.point_label, 0, wx.EXPAND) + for point in self.points: + self.sizer.Add(ObjectLine(self.parent, self, point).sizer, 0, wx.EXPAND) + + self.sizer.Add(self.line_label, 0, wx.EXPAND) + for line in self.lines: + self.sizer.Add(ObjectLine(self.parent, self, line).sizer, 0, wx.EXPAND) + + self.sizer.Add(self.conic_label, 0, wx.EXPAND) + for conic in self.conics: + self.sizer.Add(ObjectLine(self.parent, self, conic).sizer, 0, wx.EXPAND) + + + def delete_object(self, object): + for list in [self.points, self.lines, self.conics]: + try: + list.remove(object) + except ValueError: + pass + + +art_list = [ + wx.ART_ADD_BOOKMARK, + wx.ART_DEL_BOOKMARK, + wx.ART_HELP_SIDE_PANEL, + wx.ART_HELP_SETTINGS, + wx.ART_HELP_BOOK, + wx.ART_HELP_FOLDER, + wx.ART_HELP_PAGE, + wx.ART_GO_BACK, + wx.ART_GO_FORWARD, + wx.ART_GO_UP, + wx.ART_GO_DOWN, + wx.ART_GO_TO_PARENT, + wx.ART_GO_HOME, + wx.ART_FILE_OPEN, + wx.ART_FILE_SAVE, + wx.ART_FILE_SAVE_AS, + wx.ART_PRINT, + wx.ART_HELP, + wx.ART_TIP, + wx.ART_REPORT_VIEW, + wx.ART_LIST_VIEW, + wx.ART_NEW_DIR, + wx.ART_HARDDISK, + wx.ART_FLOPPY, + wx.ART_CDROM, + wx.ART_REMOVABLE, + wx.ART_FOLDER, + wx.ART_FOLDER_OPEN, + wx.ART_GO_DIR_UP, + wx.ART_EXECUTABLE_FILE, + wx.ART_NORMAL_FILE, + wx.ART_TICK_MARK, + wx.ART_CROSS_MARK, + wx.ART_ERROR, + wx.ART_QUESTION, + wx.ART_WARNING, + wx.ART_INFORMATION, + wx.ART_MISSING_IMAGE, + wx.ART_COPY, + wx.ART_CUT, + wx.ART_PASTE, + wx.ART_DELETE, + wx.ART_NEW, + wx.ART_UNDO, + wx.ART_REDO, + wx.ART_QUIT, + wx.ART_FIND, + wx.ART_FIND_AND_REPLACE + ] + +class ControlPanel(object): + + def __init__(self, parent): + + self.parent = parent + self.sizer = wx.BoxSizer(wx.HORIZONTAL) + self.state = None + self.new_point(None) + + self.field = FiniteField + self.field.base = 37 + + def _get_colour(self): + colour = self.colours.GetValue() + return {"blue": blue(self.field), + "red": red(self.field), + "green": green(self.field)}[colour] + + def _add_common(self, callback): + self.colours = wx.ComboBox(self.parent, value="blue", choices=["blue", "red", "green"], style=wx.CB_READONLY) + self.sizer.Add(self.colours, 0, wx.EXPAND) + + self.name = wx.TextCtrl(self.parent, size=(150, 1)) + self.sizer.Add(self.name, 0, wx.EXPAND) + + self.button = wx.Button(self.parent, label="ADD") + self.button.Bind(wx.EVT_BUTTON, callback) + self.sizer.Add(self.button, 0, wx.EXPAND) + + self.parent.main_sizer.Layout() + + def _spinner(self): + return wx.SpinCtrl(self.parent, min=0, max=37, initial=1) + + def _add_point_box(self): + point_names = [point.object[1] for point in self.parent.object_panel.points] + points = wx.ComboBox(self.parent, value="a", choices=point_names, style=wx.CB_READONLY) + self.sizer.Add(points, 0, wx.EXPAND) + return points + + def _add_line_box(self): + line_names = [line.object[1] for line in self.parent.object_panel.lines] + lines = wx.ComboBox(self.parent, value="a", choices=line_names, style=wx.CB_READONLY) + self.sizer.Add(lines, 0, wx.EXPAND) + return lines + + def _get_point(self, points): + point_name = points.GetValue() + for point in self.parent.object_panel.points: + if point.object[1] == point_name: + return point.object[0] + + def _get_line(self, lines): + line_name = lines.GetValue() + for line in self.parent.object_panel.lines: + if line.object[1] == line_name: + return line.object[0] + + def new_point(self, evt): + if self.state != "NEW_POINT": + self.state = "NEW_POINT" + self.sizer.Clear(True) + self.x = self._spinner() + self.y = self._spinner() + self.sizer.Add(self.x, 0, wx.EXPAND) + self.sizer.Add(self.y, 0, wx.EXPAND) + + self._add_common(self.add_point) + + def add_point(self, evt): + x = self.x.GetValue() + y = self.y.GetValue() + name = self.name.GetValue() + point = Point(self.field(x), self.field(y), self._get_colour()), name, "s", self.colours.GetValue() + self.parent.object_panel.add_point(point) + + def new_line(self, evt): + if self.state != "NEW_LINE": + self.state = "NEW_LINE" + self.sizer.Clear(True) + self.a = self._spinner() + self.b = self._spinner() + self.c = self._spinner() + self.sizer.Add(self.a, 0, wx.EXPAND) + self.sizer.Add(self.b, 0, wx.EXPAND) + self.sizer.Add(self.c, 0, wx.EXPAND) + + self._add_common(self.add_line) + + def add_line(self, evt): + a = self.a.GetValue() + b = self.b.GetValue() + c = self.c.GetValue() + name = self.name.GetValue() + line = Line(self.field(a), self.field(b), self.field(c), self._get_colour()), name, "o", self.colours.GetValue() + self.parent.object_panel.add_line(line) + + def new_conic(self, evt): + if self.state != "NEW_CONIC": + self.state = "NEW_CONIC" + self.sizer.Clear(True) + self.a = self._spinner() + self.b = self._spinner() + self.c = self._spinner() + self.d = self._spinner() + self.e = self._spinner() + self.f = self._spinner() + self.sizer.Add(self.a, 0, wx.EXPAND) + self.sizer.Add(self.b, 0, wx.EXPAND) + self.sizer.Add(self.c, 0, wx.EXPAND) + self.sizer.Add(self.d, 0, wx.EXPAND) + self.sizer.Add(self.e, 0, wx.EXPAND) + self.sizer.Add(self.f, 0, wx.EXPAND) + + self._add_common(self.add_conic) + + def add_conic(self, evt): + a = self.a.GetValue() + b = self.b.GetValue() + c = self.c.GetValue() + d = self.d.GetValue() + e = self.e.GetValue() + f = self.f.GetValue() + name = self.name.GetValue() + conic = Conic(self.field(a), self.field(b), self.field(c), self.field(d), self.field(e), self.field(f), self._get_colour()), name, "x", self.colours.GetValue() + self.parent.object_panel.add_conic(conic) + + + def new_circle(self, evt): + if self.state != "NEW_CIRCLE": + self.state = "NEW_CIRCLE" + self.sizer.Clear(True) + self.k = self._spinner() + self.sizer.Add(self.k, 0, wx.EXPAND) + + self.points = self._add_point_box() + + self._add_common(self.add_circle) + + def add_circle(self, evt): + k = self.k.GetValue() + centre = self._get_point(self.points) + name = self.name.GetValue() + if centre is not None: + conic = centre.circle(k), name, "x", self.colours.GetValue() + self.parent.object_panel.add_conic(conic) + + + def new_parabola(self, evt): + if self.state != "NEW_PARABOLA": + self.state = "NEW_PARABOLA" + self.sizer.Clear(True) + + self.points = self._add_point_box() + self.lines = self._add_line_box() + + self._add_common(self.add_parabola) + + def add_parabola(self, evt): + line_name = self.lines.GetValue() + directrix = None + focus = self._get_point(self.points) + + directrix = self._get_line(self.lines) + + if focus and directrix: + pl = PointLine(focus, directrix) + name = self.name.GetValue() + conic = pl.parabola(), name, "x", self.colours.GetValue() + self.parent.object_panel.add_conic(conic) + + + def new_altitude(self, evt): + if self.state != "NEW_ALTITUDE": + self.state = "NEW_ALTITUDE" + self.sizer.Clear(True) + + self.points = self._add_point_box() + self.lines = self._add_line_box() + + self._add_common(self.add_altitude) + + def add_altitude(self, evt): + point_ = self._get_point(self.points) + line_ = self._get_line(self.lines) + + if point_ and line_: + pl = PointLine(point_, line_) + name = self.name.GetValue() + altitude = pl.altitude(), name, "o", self.colours.GetValue() + self.parent.object_panel.add_line(altitude) + + def new_parallel(self, evt): + if self.state != "NEW_PARALLEL": + self.state = "NEW_PARALLEL" + self.sizer.Clear(True) + + self.points = self._add_point_box() + self.lines = self._add_line_box() + + self._add_common(self.add_parallel) + + def add_parallel(self, evt): + point_ = self._get_point(self.points) + line_ = self._get_line(self.lines) + + if point_ and line_: + pl = PointLine(point_, line_) + name = self.name.GetValue() + parallel = pl.parallel(), name, "o", self.colours.GetValue() + self.parent.object_panel.add_line(parallel) + + def new_conick(self, evt): + if self.state != "NEW_CONICK": + self.state = "NEW_CONICK" + self.sizer.Clear(True) + + self.k = self._spinner() + self.sizer.Add(self.k, 0, wx.EXPAND) + + self.points = self._add_point_box() + self.lines = self._add_line_box() + + self._add_common(self.add_conick) + + + def add_conick(self, evt): + k = self.k.GetValue() + focus = self._get_point(self.points) + directrix = self._get_line(self.lines) + + if focus and directrix: + pl = PointLine(focus, directrix) + name = self.name.GetValue() + conic = pl.conic(k), name, "x", self.colours.GetValue() + self.parent.object_panel.add_conic(conic) + + + def new_midpoint(self, evt): + if self.state != "NEW_MIDPOINT": + self.state = "NEW_MIDPOINT" + self.sizer.Clear(True) + + self.points1 = self._add_point_box() + self.points2 = self._add_point_box() + + self._add_common(self.add_midpoint) + + def add_midpoint(self, evt): + p1 = self._get_point(self.points1) + p2 = self._get_point(self.points2) + + if p1 and p2: + line_segment = LineSegment(p1, p2) + name = self.name.GetValue() + mid = line_segment.midpoint(), name, "s", self.colours.GetValue() + self.parent.object_panel.add_point(mid) + + def new_quadrola(self, evt): + if self.state != "NEW_QUADROLA": + self.state = "NEW_QUADROLA" + self.sizer.Clear(True) + + self.k = self._spinner() + self.sizer.Add(self.k, 0, wx.EXPAND) + + self.points1 = self._add_point_box() + self.points2 = self._add_point_box() + + self._add_common(self.add_quadrola) + + def add_quadrola(self, evt): + k = self.k.GetValue() + p1 = self._get_point(self.points1) + p2 = self._get_point(self.points2) + + if p1 and p2: + line_segment = LineSegment(p1, p2) + name = self.name.GetValue() + quadrola = line_segment.quadrola(k), name, "x", self.colours.GetValue() + self.parent.object_panel.add_conic(quadrola) + + def new_grammola(self, evt): + if self.state != "NEW_GRAMMOLA": + self.state = "NEW_GRAMMOLA" + self.sizer.Clear(True) + + self.k = self._spinner() + self.sizer.Add(self.k, 0, wx.EXPAND) + + self.lines1 = self._add_line_box() + self.lines2 = self._add_line_box() + + self._add_common(self.add_grammola) + + def add_grammola(self, evt): + k = self.k.GetValue() + l1 = self._get_line(self.lines1) + l2 = self._get_line(self.lines2) + + if l1 and l2: + vertex = Vertex(l1, l2) + name = self.name.GetValue() + grammola = vertex.grammola(k), name, "x", self.colours.GetValue() + self.parent.object_panel.add_conic(grammola) + + + def new_reflection(self, evt): + if self.state != "NEW_REFLECTION": + self.state = "NEW_REFLECTION" + self.sizer.Clear(True) + + self.points = self._add_point_box() + self.lines = self._add_line_box() + + self._add_common(self.add_reflection) + + def add_reflection(self, evt): + point = self._get_point(self.points) + line = self._get_line(self.lines) + + if point and line: + point_line = PointLine(point, line) + name = self.name.GetValue() + ref = point_line.reflection(), name, "s", self.colours.GetValue() + self.parent.object_panel.add_point(ref) + + + +class FinitePlotFrame(wx.Frame): + def __init__(self, *args, **kwargs): + wx.Frame.__init__(self, *args, **kwargs) + + self.main_sizer = wx.BoxSizer(wx.VERTICAL) + + self.plot = FinitePlotWindow(self) + self.object_panel = ObjectPanel(self, self.plot) + self.control_panel = ControlPanel(self) + + self.plot.draw() + + + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(self.plot, 1, wx.EXPAND) + sizer.Add(self.object_panel.sizer, 0, wx.EXPAND) + + self.main_sizer.Add(self.control_panel.sizer, 0, wx.EXPAND) + self.main_sizer.Add(sizer, 0, wx.EXPAND) + + self.SetSizer(self.main_sizer) + + ADD_POINT = wx.NewId() + ADD_LINE = wx.NewId() + ADD_CONIC = wx.NewId() + ADD_CIRCLE = wx.NewId() + ADD_PARABOLA = wx.NewId() + ADD_CONICK = wx.NewId() + ADD_ALTITUDE = wx.NewId() + ADD_PARALLEL = wx.NewId() + ADD_MIDPOINT = wx.NewId() + ADD_QUADROLA = wx.NewId() + ADD_GRAMMOLA = wx.NewId() + ADD_REFLECTION = wx.NewId() + + self.toolbar = self.CreateToolBar(wx.TB_TEXT|wx.NO_BORDER|wx.TB_HORIZONTAL|wx.TB_3DBUTTONS) + self.toolbar.AddLabelTool(ADD_POINT, "Add Point", wx.NullBitmap) + self.toolbar.AddLabelTool(ADD_LINE, "Add Line", wx.NullBitmap) + self.toolbar.AddLabelTool(ADD_CONIC, "Add Conic", wx.NullBitmap, shortHelp="ber") + self.toolbar.AddLabelTool(ADD_CIRCLE, "Add Circle", wx.NullBitmap) + self.toolbar.AddLabelTool(ADD_PARABOLA, "Add Parabola", wx.NullBitmap) + self.toolbar.AddLabelTool(ADD_CONICK, "Add Conic(2)", wx.NullBitmap) + self.toolbar.AddLabelTool(ADD_ALTITUDE, "Add Altitude", wx.NullBitmap) + self.toolbar.AddLabelTool(ADD_PARALLEL, "Add Parallel", wx.NullBitmap) + self.toolbar.AddLabelTool(ADD_QUADROLA, "Add Quadrola", wx.NullBitmap) + self.toolbar.AddLabelTool(ADD_GRAMMOLA, "Add Grammola", wx.NullBitmap) + self.toolbar.AddLabelTool(ADD_REFLECTION, "Add Relfection", wx.NullBitmap) + + self.toolbar.Realize() + + self.Bind(wx.EVT_TOOL, self.control_panel.new_point, id=ADD_POINT) + self.Bind(wx.EVT_TOOL, self.control_panel.new_line, id=ADD_LINE) + self.Bind(wx.EVT_TOOL, self.control_panel.new_conic, id=ADD_CONIC) + self.Bind(wx.EVT_TOOL, self.control_panel.new_circle, id=ADD_CIRCLE) + self.Bind(wx.EVT_TOOL, self.control_panel.new_parabola, id=ADD_PARABOLA) + self.Bind(wx.EVT_TOOL, self.control_panel.new_conick, id=ADD_CONICK) + self.Bind(wx.EVT_TOOL, self.control_panel.new_altitude, id=ADD_ALTITUDE) + self.Bind(wx.EVT_TOOL, self.control_panel.new_parallel, id=ADD_PARALLEL) + self.Bind(wx.EVT_TOOL, self.control_panel.new_midpoint, id=ADD_MIDPOINT) + self.Bind(wx.EVT_TOOL, self.control_panel.new_quadrola, id=ADD_QUADROLA) + self.Bind(wx.EVT_TOOL, self.control_panel.new_grammola, id=ADD_GRAMMOLA) + self.Bind(wx.EVT_TOOL, self.control_panel.new_reflection, id=ADD_REFLECTION) + + + +class FinitePlotWindow(wx.Window): + def __init__(self, parent, *args, **kwargs): + wx.Window.__init__(self, parent, *args, **kwargs) + self.parent = parent + self.lines = [] + self.figure = Figure() + self.canvas = FigureCanvasWxAgg(self, -1, self.figure) + #self.canvas.callbacks.connect('button_press_event', self.mouseDown) + #self.canvas.callbacks.connect('motion_notify_event', self.mouseMotion) + #self.canvas.callbacks.connect('button_release_event', self.mouseUp) + self.state = '' + self.mouseInfo = (None, None, None, None) + #self.f0 = Param(2., minimum=0., maximum=6.) + #self.A = Param(1., minimum=0.01, maximum=2.) + self.Bind(wx.EVT_SIZE, self.sizeHandler) + + + def sizeHandler(self, *args, **kwargs): + self.canvas.SetSize(self.GetSize()) + + def draw(self): + if not hasattr(self, 'ax'): + self.ax = self.figure.add_subplot(111) + ax = self.ax + ax.clear() + + handles = [] + labels = [] + self.field = self.parent.object_panel.field + + for object, name, marker, color in self.parent.object_panel.get_objects(): + xs = [] + ys = [] + l = object + for x in range(self.field.base): + for y in range(self.field.base): + if object.eval(x, y) == 0: + xs.append(x) + ys.append(y) + handles.append(ax.scatter(xs, ys, marker=marker, s=100, color=color)) + labels.append(name) + + ax.set_xlim(-0.5, self.field.base - 0.5) + ax.set_ylim(-0.5, self.field.base - 0.5) + + ax.xaxis.set_major_locator( IndexLocator(-0.5, 1) ) + ax.xaxis.set_minor_locator( IndexLocator(0, 1) ) + ax.yaxis.set_major_locator( IndexLocator(-0.5, 1) ) + ax.yaxis.set_minor_locator( IndexLocator(0, 1) ) + + ax.xaxis.set_major_formatter( NullFormatter() ) + ax.xaxis.set_minor_formatter( ScalarFormatter() ) + ax.yaxis.set_major_formatter( NullFormatter() ) + ax.yaxis.set_minor_formatter( ScalarFormatter() ) + + ax.set_xticks(range(0, self.field.base), minor=True) + ax.set_yticks(range(0, self.field.base), minor=True) + + ax.set_xticks([x + 0.5 for x in range(0, self.field.base)]) + ax.set_yticks([x + 0.5 for x in range(0, self.field.base)]) + + ax.grid(True) + self.repaint() + + + def repaint(self): + self.canvas.draw() + + +class App(wx.App): + def OnInit(self): + sys.stdout = stdout + sys.stderr = stderr + self.frame1 = FinitePlotFrame(parent=None, title="Finite Field Geometry Demo", size=(640, 480)) + self.frame1.Show() + return True + + + +import sys +stdout = sys.stdout +stderr = sys.stderr +app = App() +app.MainLoop() + + + diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 0000000..139597f --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,2 @@ + + diff --git a/doc/report/hunsrt.bst b/doc/report/hunsrt.bst new file mode 100644 index 0000000..ffca276 --- /dev/null +++ b/doc/report/hunsrt.bst @@ -0,0 +1,974 @@ +% hunsrt: adds eprint field (www-admin@xxx.lanl.gov) +% an extension of: +% BibTeX standard bibliography style `unsrt' + % version 0.99a for BibTeX versions 0.99a or later, LaTeX version 2.09. + % Copyright (C) 1985, all rights reserved. + % Copying of this file is authorized only if either + % (1) you make absolutely no changes to your copy, including name, or + % (2) if you do make changes, you name it something other than + % btxbst.doc, plain.bst, unsrt.bst, alpha.bst, and abbrv.bst. + % This restriction helps ensure that all standard styles are identical. + % The file btxbst.doc has the documentation for this style. + +ENTRY + { address + author + booktitle + chapter + edition + editor + eprint + howpublished + institution + journal + key + month + note + number + organization + pages + publisher + school + series + title + type + volume + year + } + {} + { label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state mid.sentence = + { ", " * write$ } + { output.state after.block = + { add.period$ write$ + newline$ + "\newblock " write$ + } + { output.state before.all = + 'write$ + { add.period$ " " * write$ } + if$ + } + if$ + mid.sentence 'output.state := + } + if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + 'output.nonnull + if$ +} + +FUNCTION {output.bibitem} +{ newline$ + "\bibitem{" write$ + cite$ write$ + "}" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ add.period$ + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = + 'skip$ + { after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { s nameptr "{ff~}{vv~}{ll}{, jj}" format.name$ 't := + nameptr #1 > + { namesleft #1 > + { ", " * t * } + { numnames #2 > + { "," * } + 'skip$ + if$ + t "others" = + { " et~al." * } + { " and " * t * } + if$ + } + if$ + } + 't + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ +} + +FUNCTION {format.authors} +{ author empty$ + { "" } + { author format.names } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor format.names + editor num.names$ #1 > + { ", editors" * } + { ", editor" * } + if$ + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { title "t" change.case$ } + if$ +} + +FUNCTION {format.eprint} +{ eprint empty$ + { "" } + { eprint } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = + { t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } + { "-" * + t #2 global.max$ substring$ 't := + } + while$ + } + if$ + } + { t #1 #1 substring$ * + t #2 global.max$ substring$ 't := + } + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ + { "" } + { "there's a month but no year in " cite$ * warning$ + month + } + if$ + } + { month empty$ + 'year + { month " " * year * } + if$ + } + if$ +} + +FUNCTION {format.btitle} +{ title emphasize +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { "volume" volume tie.or.space.connect + series empty$ + 'skip$ + { " of " * series emphasize * } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ + { series field.or.null } + { output.state mid.sentence = + { "number" } + { "Number" } + if$ + number tie.or.space.connect + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { " in " * series * } + if$ + } + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { output.state mid.sentence = + { edition "l" change.case$ " edition" * } + { edition "t" change.case$ " edition" * } + if$ + } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or + { #1 'multiresult := } + { t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check + { "pages" pages n.dashify tie.or.space.connect } + { "page" pages tie.or.space.connect } + if$ + } + if$ +} + +FUNCTION {format.vol.num.pages} +{ volume field.or.null + number empty$ + 'skip$ + { "(" number * ")" * * + volume empty$ + { "there's a number but no volume in " cite$ * warning$ } + 'skip$ + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ + { pop$ format.pages } + { ":" * pages n.dashify * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ + { "chapter" } + { type "l" change.case$ } + if$ + chapter tie.or.space.connect + pages empty$ + 'skip$ + { ", " * format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { editor empty$ + { "In " booktitle emphasize * } + { "In " format.editors * ", " * booktitle emphasize * } + if$ + } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + } + if$ +} + +FUNCTION {format.tr.number} +{ type empty$ + { "Technical Report" } + 'type + if$ + number empty$ + { "t" change.case$ } + { number tie.or.space.connect } + if$ +} + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ + { "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" + } + { "In {\em " journal * "\/}" * } + if$ + } + { "In " key * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ editor #1 "{vv~}{ll}" format.name$ + editor num.names$ duplicate$ + #2 > + { pop$ " et~al." * } + { #2 < + 'skip$ + { editor #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" = + { " et~al." * } + { " and " * editor #2 "{vv~}{ll}" format.name$ * } + if$ + } + if$ + } + if$ +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + "In " + } + { "Volume" volume tie.or.space.connect + " of " * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { "{\em " * series * "\/}" * } + if$ + } + { key * } + if$ + } + { format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ + { booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "In {\em " booktitle * "\/}" * } + if$ + } + { "In " key * } + if$ + } + { "In " format.crossref.editor * } + if$ + " \cite{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { journal emphasize "journal" output.check + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + format.eprint output + new.block + note output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + format.eprint output + new.block + note output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + format.authors output + new.block + format.title "title" output.check + howpublished address new.block.checkb + howpublished output + address output + format.date output + format.eprint output + new.block + note output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ + { "author and editor" editor either.or.check } + 'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + publisher "publisher" output.check + address output + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + format.eprint output + new.block + note output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + publisher "publisher" output.check + address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + format.eprint output + new.block + note output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.pages output + address empty$ + { organization publisher new.sentence.checkb + organization output + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + organization output + publisher output + } + if$ + } + { format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + format.eprint output + new.block + note output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + author empty$ + { organization empty$ + 'skip$ + { organization output.nonnull + address output + } + if$ + } + { format.authors output.nonnull } + if$ + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ + { address new.block.checka + address output + } + 'skip$ + if$ + } + { organization address new.block.checkb + organization output + address output + } + if$ + format.edition output + format.date output + format.eprint output + new.block + note output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + "Master's thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + format.eprint output + new.block + note output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + format.authors output + title howpublished new.block.checkb + format.title output + howpublished new.block.checka + howpublished output + format.date output + format.eprint output + new.block + note output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + format.authors "author" output.check + new.block + format.btitle "title" output.check + new.block + "PhD thesis" format.thesis.type output.nonnull + school "school" output.check + address output + format.date "year" output.check + format.eprint output + new.block + note output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + editor empty$ + { organization output } + { format.editors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + format.number.series output + address empty$ + { editor empty$ + { publisher new.sentence.checka } + { organization publisher new.sentence.checkb + organization output + } + if$ + publisher output + format.date "year" output.check + } + { address output.nonnull + format.date "year" output.check + new.sentence + editor empty$ + 'skip$ + { organization output } + if$ + publisher output + } + if$ + format.eprint output + new.block + note output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + institution "institution" output.check + address output + format.date "year" output.check + format.eprint output + new.block + note output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + note "note" output.check + format.date output + format.eprint output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"January"} + +MACRO {feb} {"February"} + +MACRO {mar} {"March"} + +MACRO {apr} {"April"} + +MACRO {may} {"May"} + +MACRO {jun} {"June"} + +MACRO {jul} {"July"} + +MACRO {aug} {"August"} + +MACRO {sep} {"September"} + +MACRO {oct} {"October"} + +MACRO {nov} {"November"} + +MACRO {dec} {"December"} + +MACRO {acmcs} {"ACM Computing Surveys"} + +MACRO {acta} {"Acta Informatica"} + +MACRO {cacm} {"Communications of the ACM"} + +MACRO {ibmjrd} {"IBM Journal of Research and Development"} + +MACRO {ibmsj} {"IBM Systems Journal"} + +MACRO {ieeese} {"IEEE Transactions on Software Engineering"} + +MACRO {ieeetc} {"IEEE Transactions on Computers"} + +MACRO {ieeetcad} + {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"} + +MACRO {ipl} {"Information Processing Letters"} + +MACRO {jacm} {"Journal of the ACM"} + +MACRO {jcss} {"Journal of Computer and System Sciences"} + +MACRO {scp} {"Science of Computer Programming"} + +MACRO {sicomp} {"SIAM Journal on Computing"} + +MACRO {tocs} {"ACM Transactions on Computer Systems"} + +MACRO {tods} {"ACM Transactions on Database Systems"} + +MACRO {tog} {"ACM Transactions on Graphics"} + +MACRO {toms} {"ACM Transactions on Mathematical Software"} + +MACRO {toois} {"ACM Transactions on Office Information Systems"} + +MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"} + +MACRO {tcs} {"Theoretical Computer Science"} + +READ + +STRINGS { longest.label } + +INTEGERS { number.label longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ + "\begin{thebibliography}{" longest.label * "}" * write$ newline$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ newline$ + "\end{thebibliography}" write$ newline$ +} + +EXECUTE {end.bib} diff --git a/pygeom.egg-info/PKG-INFO b/pygeom.egg-info/PKG-INFO new file mode 100644 index 0000000..e85fe78 --- /dev/null +++ b/pygeom.egg-info/PKG-INFO @@ -0,0 +1,33 @@ +Metadata-Version: 1.0 +Name: pygeom +Version: 0.0.1 +Summary: a Python package for performing calculations in planar universal geometry +Home-page: https://github.com/timleslie/pygeom +Author: Tim Leslie +Author-email: tim.leslie@gmail.com +License: unspecified +Description: pygeom a Python package for performing calculations in planar universal geometry + + + + + + + + Oct 30, 2014 marchon added package to make installation easier + no core modifications, only + - README + - HISTORY + - DESCRIPTIONS + - REFERENCE + * PlanarUniversalGeometry.pdf + * Trigonometry-The-Study-Of-Circles.pdf + * Universal-Hyperbolic-Geometry-I-Trigonometry.pdf + * Universal-Hyperbolic-Geometry-II-A-pictorial-overview.pdf + * Universal-Hyperbolic-Geometry-Summary-of-NJWildbergers-online-lecture-series.pdf + * WhyEllipsesAreNotEllipticCurves.pdf + + Jun 7, 2012 timleslie uploaded pygeom to github on + + +Platform: UNKNOWN diff --git a/pygeom.egg-info/SOURCES.txt b/pygeom.egg-info/SOURCES.txt new file mode 100644 index 0000000..9279f2f --- /dev/null +++ b/pygeom.egg-info/SOURCES.txt @@ -0,0 +1,19 @@ +README +setup.py +pygeom/__init__.py +pygeom/core.py +pygeom/field.py +pygeom/fourier.py +pygeom/geometry.py +pygeom/pairs.py +pygeom/plot.py +pygeom/point.py +pygeom/polygon.py +pygeom/util.py +pygeom/version.py +pygeom/wx_demo.py +pygeom.egg-info/PKG-INFO +pygeom.egg-info/SOURCES.txt +pygeom.egg-info/dependency_links.txt +pygeom.egg-info/not-zip-safe +pygeom.egg-info/top_level.txt \ No newline at end of file diff --git a/pygeom.egg-info/dependency_links.txt b/pygeom.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/pygeom.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/pygeom.egg-info/not-zip-safe b/pygeom.egg-info/not-zip-safe new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/pygeom.egg-info/not-zip-safe @@ -0,0 +1 @@ + diff --git a/pygeom.egg-info/top_level.txt b/pygeom.egg-info/top_level.txt new file mode 100644 index 0000000..6fcb5c6 --- /dev/null +++ b/pygeom.egg-info/top_level.txt @@ -0,0 +1 @@ +pygeom diff --git a/pygeom/version.py b/pygeom/version.py new file mode 100644 index 0000000..94c5d1d --- /dev/null +++ b/pygeom/version.py @@ -0,0 +1 @@ +__version__ = '0.0.1' diff --git a/scripts/plot.py b/scripts/plot.py index 653a4f1..e6daa12 100644 --- a/scripts/plot.py +++ b/scripts/plot.py @@ -3,7 +3,7 @@ from numpy import zeros from pygeom.field import FiniteField -from pygeom.point import Line +from pygeom.core import Line f = FiniteField f.base = 13 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..86d02c7 --- /dev/null +++ b/setup.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +import os +import sys + +import pygeom +from pygeom import version + + +from codecs import open + +try: + from setuptools import setup +except ImportError: + from distutils.core import setup + +if sys.argv[-1] == 'publish': + os.system('python setup.py sdist upload') + sys.exit() + +packages = [ + 'pygeom', +] + +requires = [] + +with open('README', 'r', 'utf-8') as f: + readme = f.read() +with open('HISTORY', 'r', 'utf-8') as f: + history = f.read() + +setup( + name='pygeom', + version=version.__version__, + description='a Python package for performing calculations in planar universal geometry', + long_description=readme + '\n\n' + history, + author='Tim Leslie', + author_email='tim.leslie@gmail.com', + url='https://github.com/timleslie/pygeom', + packages=packages, + package_data={'': ['LICENSE', 'NOTICE']}, + package_dir={'pygeom': 'pygeom'}, + include_package_data=True, + install_requires=requires, + license='unspecified', + zip_safe=False, + classifiers=( + ), + extras_require={ + }, +)