Spaces:
Sleeping
Sleeping
from sympy.core.basic import Basic | |
from sympy.core.numbers import (I, Rational, pi) | |
from sympy.core.parameters import evaluate | |
from sympy.core.singleton import S | |
from sympy.core.symbol import Symbol | |
from sympy.core.sympify import sympify | |
from sympy.functions.elementary.miscellaneous import sqrt | |
from sympy.geometry import Line, Point, Point2D, Point3D, Line3D, Plane | |
from sympy.geometry.entity import rotate, scale, translate, GeometryEntity | |
from sympy.matrices import Matrix | |
from sympy.utilities.iterables import subsets, permutations, cartes | |
from sympy.utilities.misc import Undecidable | |
from sympy.testing.pytest import raises, warns | |
def test_point(): | |
x = Symbol('x', real=True) | |
y = Symbol('y', real=True) | |
x1 = Symbol('x1', real=True) | |
x2 = Symbol('x2', real=True) | |
y1 = Symbol('y1', real=True) | |
y2 = Symbol('y2', real=True) | |
half = S.Half | |
p1 = Point(x1, x2) | |
p2 = Point(y1, y2) | |
p3 = Point(0, 0) | |
p4 = Point(1, 1) | |
p5 = Point(0, 1) | |
line = Line(Point(1, 0), slope=1) | |
assert p1 in p1 | |
assert p1 not in p2 | |
assert p2.y == y2 | |
assert (p3 + p4) == p4 | |
assert (p2 - p1) == Point(y1 - x1, y2 - x2) | |
assert -p2 == Point(-y1, -y2) | |
raises(TypeError, lambda: Point(1)) | |
raises(ValueError, lambda: Point([1])) | |
raises(ValueError, lambda: Point(3, I)) | |
raises(ValueError, lambda: Point(2*I, I)) | |
raises(ValueError, lambda: Point(3 + I, I)) | |
assert Point(34.05, sqrt(3)) == Point(Rational(681, 20), sqrt(3)) | |
assert Point.midpoint(p3, p4) == Point(half, half) | |
assert Point.midpoint(p1, p4) == Point(half + half*x1, half + half*x2) | |
assert Point.midpoint(p2, p2) == p2 | |
assert p2.midpoint(p2) == p2 | |
assert p1.origin == Point(0, 0) | |
assert Point.distance(p3, p4) == sqrt(2) | |
assert Point.distance(p1, p1) == 0 | |
assert Point.distance(p3, p2) == sqrt(p2.x**2 + p2.y**2) | |
raises(TypeError, lambda: Point.distance(p1, 0)) | |
raises(TypeError, lambda: Point.distance(p1, GeometryEntity())) | |
# distance should be symmetric | |
assert p1.distance(line) == line.distance(p1) | |
assert p4.distance(line) == line.distance(p4) | |
assert Point.taxicab_distance(p4, p3) == 2 | |
assert Point.canberra_distance(p4, p5) == 1 | |
raises(ValueError, lambda: Point.canberra_distance(p3, p3)) | |
p1_1 = Point(x1, x1) | |
p1_2 = Point(y2, y2) | |
p1_3 = Point(x1 + 1, x1) | |
assert Point.is_collinear(p3) | |
with warns(UserWarning, test_stacklevel=False): | |
assert Point.is_collinear(p3, Point(p3, dim=4)) | |
assert p3.is_collinear() | |
assert Point.is_collinear(p3, p4) | |
assert Point.is_collinear(p3, p4, p1_1, p1_2) | |
assert Point.is_collinear(p3, p4, p1_1, p1_3) is False | |
assert Point.is_collinear(p3, p3, p4, p5) is False | |
raises(TypeError, lambda: Point.is_collinear(line)) | |
raises(TypeError, lambda: p1_1.is_collinear(line)) | |
assert p3.intersection(Point(0, 0)) == [p3] | |
assert p3.intersection(p4) == [] | |
assert p3.intersection(line) == [] | |
with warns(UserWarning, test_stacklevel=False): | |
assert Point.intersection(Point(0, 0, 0), Point(0, 0)) == [Point(0, 0, 0)] | |
x_pos = Symbol('x', positive=True) | |
p2_1 = Point(x_pos, 0) | |
p2_2 = Point(0, x_pos) | |
p2_3 = Point(-x_pos, 0) | |
p2_4 = Point(0, -x_pos) | |
p2_5 = Point(x_pos, 5) | |
assert Point.is_concyclic(p2_1) | |
assert Point.is_concyclic(p2_1, p2_2) | |
assert Point.is_concyclic(p2_1, p2_2, p2_3, p2_4) | |
for pts in permutations((p2_1, p2_2, p2_3, p2_5)): | |
assert Point.is_concyclic(*pts) is False | |
assert Point.is_concyclic(p4, p4 * 2, p4 * 3) is False | |
assert Point(0, 0).is_concyclic((1, 1), (2, 2), (2, 1)) is False | |
assert Point.is_concyclic(Point(0, 0, 0, 0), Point(1, 0, 0, 0), Point(1, 1, 0, 0), Point(1, 1, 1, 0)) is False | |
assert p1.is_scalar_multiple(p1) | |
assert p1.is_scalar_multiple(2*p1) | |
assert not p1.is_scalar_multiple(p2) | |
assert Point.is_scalar_multiple(Point(1, 1), (-1, -1)) | |
assert Point.is_scalar_multiple(Point(0, 0), (0, -1)) | |
# test when is_scalar_multiple can't be determined | |
raises(Undecidable, lambda: Point.is_scalar_multiple(Point(sympify("x1%y1"), sympify("x2%y2")), Point(0, 1))) | |
assert Point(0, 1).orthogonal_direction == Point(1, 0) | |
assert Point(1, 0).orthogonal_direction == Point(0, 1) | |
assert p1.is_zero is None | |
assert p3.is_zero | |
assert p4.is_zero is False | |
assert p1.is_nonzero is None | |
assert p3.is_nonzero is False | |
assert p4.is_nonzero | |
assert p4.scale(2, 3) == Point(2, 3) | |
assert p3.scale(2, 3) == p3 | |
assert p4.rotate(pi, Point(0.5, 0.5)) == p3 | |
assert p1.__radd__(p2) == p1.midpoint(p2).scale(2, 2) | |
assert (-p3).__rsub__(p4) == p3.midpoint(p4).scale(2, 2) | |
assert p4 * 5 == Point(5, 5) | |
assert p4 / 5 == Point(0.2, 0.2) | |
assert 5 * p4 == Point(5, 5) | |
raises(ValueError, lambda: Point(0, 0) + 10) | |
# Point differences should be simplified | |
assert Point(x*(x - 1), y) - Point(x**2 - x, y + 1) == Point(0, -1) | |
a, b = S.Half, Rational(1, 3) | |
assert Point(a, b).evalf(2) == \ | |
Point(a.n(2), b.n(2), evaluate=False) | |
raises(ValueError, lambda: Point(1, 2) + 1) | |
# test project | |
assert Point.project((0, 1), (1, 0)) == Point(0, 0) | |
assert Point.project((1, 1), (1, 0)) == Point(1, 0) | |
raises(ValueError, lambda: Point.project(p1, Point(0, 0))) | |
# test transformations | |
p = Point(1, 0) | |
assert p.rotate(pi/2) == Point(0, 1) | |
assert p.rotate(pi/2, p) == p | |
p = Point(1, 1) | |
assert p.scale(2, 3) == Point(2, 3) | |
assert p.translate(1, 2) == Point(2, 3) | |
assert p.translate(1) == Point(2, 1) | |
assert p.translate(y=1) == Point(1, 2) | |
assert p.translate(*p.args) == Point(2, 2) | |
# Check invalid input for transform | |
raises(ValueError, lambda: p3.transform(p3)) | |
raises(ValueError, lambda: p.transform(Matrix([[1, 0], [0, 1]]))) | |
# test __contains__ | |
assert 0 in Point(0, 0, 0, 0) | |
assert 1 not in Point(0, 0, 0, 0) | |
# test affine_rank | |
assert Point.affine_rank() == -1 | |
def test_point3D(): | |
x = Symbol('x', real=True) | |
y = Symbol('y', real=True) | |
x1 = Symbol('x1', real=True) | |
x2 = Symbol('x2', real=True) | |
x3 = Symbol('x3', real=True) | |
y1 = Symbol('y1', real=True) | |
y2 = Symbol('y2', real=True) | |
y3 = Symbol('y3', real=True) | |
half = S.Half | |
p1 = Point3D(x1, x2, x3) | |
p2 = Point3D(y1, y2, y3) | |
p3 = Point3D(0, 0, 0) | |
p4 = Point3D(1, 1, 1) | |
p5 = Point3D(0, 1, 2) | |
assert p1 in p1 | |
assert p1 not in p2 | |
assert p2.y == y2 | |
assert (p3 + p4) == p4 | |
assert (p2 - p1) == Point3D(y1 - x1, y2 - x2, y3 - x3) | |
assert -p2 == Point3D(-y1, -y2, -y3) | |
assert Point(34.05, sqrt(3)) == Point(Rational(681, 20), sqrt(3)) | |
assert Point3D.midpoint(p3, p4) == Point3D(half, half, half) | |
assert Point3D.midpoint(p1, p4) == Point3D(half + half*x1, half + half*x2, | |
half + half*x3) | |
assert Point3D.midpoint(p2, p2) == p2 | |
assert p2.midpoint(p2) == p2 | |
assert Point3D.distance(p3, p4) == sqrt(3) | |
assert Point3D.distance(p1, p1) == 0 | |
assert Point3D.distance(p3, p2) == sqrt(p2.x**2 + p2.y**2 + p2.z**2) | |
p1_1 = Point3D(x1, x1, x1) | |
p1_2 = Point3D(y2, y2, y2) | |
p1_3 = Point3D(x1 + 1, x1, x1) | |
Point3D.are_collinear(p3) | |
assert Point3D.are_collinear(p3, p4) | |
assert Point3D.are_collinear(p3, p4, p1_1, p1_2) | |
assert Point3D.are_collinear(p3, p4, p1_1, p1_3) is False | |
assert Point3D.are_collinear(p3, p3, p4, p5) is False | |
assert p3.intersection(Point3D(0, 0, 0)) == [p3] | |
assert p3.intersection(p4) == [] | |
assert p4 * 5 == Point3D(5, 5, 5) | |
assert p4 / 5 == Point3D(0.2, 0.2, 0.2) | |
assert 5 * p4 == Point3D(5, 5, 5) | |
raises(ValueError, lambda: Point3D(0, 0, 0) + 10) | |
# Test coordinate properties | |
assert p1.coordinates == (x1, x2, x3) | |
assert p2.coordinates == (y1, y2, y3) | |
assert p3.coordinates == (0, 0, 0) | |
assert p4.coordinates == (1, 1, 1) | |
assert p5.coordinates == (0, 1, 2) | |
assert p5.x == 0 | |
assert p5.y == 1 | |
assert p5.z == 2 | |
# Point differences should be simplified | |
assert Point3D(x*(x - 1), y, 2) - Point3D(x**2 - x, y + 1, 1) == \ | |
Point3D(0, -1, 1) | |
a, b, c = S.Half, Rational(1, 3), Rational(1, 4) | |
assert Point3D(a, b, c).evalf(2) == \ | |
Point(a.n(2), b.n(2), c.n(2), evaluate=False) | |
raises(ValueError, lambda: Point3D(1, 2, 3) + 1) | |
# test transformations | |
p = Point3D(1, 1, 1) | |
assert p.scale(2, 3) == Point3D(2, 3, 1) | |
assert p.translate(1, 2) == Point3D(2, 3, 1) | |
assert p.translate(1) == Point3D(2, 1, 1) | |
assert p.translate(z=1) == Point3D(1, 1, 2) | |
assert p.translate(*p.args) == Point3D(2, 2, 2) | |
# Test __new__ | |
assert Point3D(0.1, 0.2, evaluate=False, on_morph='ignore').args[0].is_Float | |
# Test length property returns correctly | |
assert p.length == 0 | |
assert p1_1.length == 0 | |
assert p1_2.length == 0 | |
# Test are_colinear type error | |
raises(TypeError, lambda: Point3D.are_collinear(p, x)) | |
# Test are_coplanar | |
assert Point.are_coplanar() | |
assert Point.are_coplanar((1, 2, 0), (1, 2, 0), (1, 3, 0)) | |
assert Point.are_coplanar((1, 2, 0), (1, 2, 3)) | |
with warns(UserWarning, test_stacklevel=False): | |
raises(ValueError, lambda: Point2D.are_coplanar((1, 2), (1, 2, 3))) | |
assert Point3D.are_coplanar((1, 2, 0), (1, 2, 3)) | |
assert Point.are_coplanar((0, 0, 0), (1, 1, 0), (1, 1, 1), (1, 2, 1)) is False | |
planar2 = Point3D(1, -1, 1) | |
planar3 = Point3D(-1, 1, 1) | |
assert Point3D.are_coplanar(p, planar2, planar3) == True | |
assert Point3D.are_coplanar(p, planar2, planar3, p3) == False | |
assert Point.are_coplanar(p, planar2) | |
planar2 = Point3D(1, 1, 2) | |
planar3 = Point3D(1, 1, 3) | |
assert Point3D.are_coplanar(p, planar2, planar3) # line, not plane | |
plane = Plane((1, 2, 1), (2, 1, 0), (3, 1, 2)) | |
assert Point.are_coplanar(*[plane.projection(((-1)**i, i)) for i in range(4)]) | |
# all 2D points are coplanar | |
assert Point.are_coplanar(Point(x, y), Point(x, x + y), Point(y, x + 2)) is True | |
# Test Intersection | |
assert planar2.intersection(Line3D(p, planar3)) == [Point3D(1, 1, 2)] | |
# Test Scale | |
assert planar2.scale(1, 1, 1) == planar2 | |
assert planar2.scale(2, 2, 2, planar3) == Point3D(1, 1, 1) | |
assert planar2.scale(1, 1, 1, p3) == planar2 | |
# Test Transform | |
identity = Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) | |
assert p.transform(identity) == p | |
trans = Matrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1], [0, 0, 0, 1]]) | |
assert p.transform(trans) == Point3D(2, 2, 2) | |
raises(ValueError, lambda: p.transform(p)) | |
raises(ValueError, lambda: p.transform(Matrix([[1, 0], [0, 1]]))) | |
# Test Equals | |
assert p.equals(x1) == False | |
# Test __sub__ | |
p_4d = Point(0, 0, 0, 1) | |
with warns(UserWarning, test_stacklevel=False): | |
assert p - p_4d == Point(1, 1, 1, -1) | |
p_4d3d = Point(0, 0, 1, 0) | |
with warns(UserWarning, test_stacklevel=False): | |
assert p - p_4d3d == Point(1, 1, 0, 0) | |
def test_Point2D(): | |
# Test Distance | |
p1 = Point2D(1, 5) | |
p2 = Point2D(4, 2.5) | |
p3 = (6, 3) | |
assert p1.distance(p2) == sqrt(61)/2 | |
assert p2.distance(p3) == sqrt(17)/2 | |
# Test coordinates | |
assert p1.x == 1 | |
assert p1.y == 5 | |
assert p2.x == 4 | |
assert p2.y == S(5)/2 | |
assert p1.coordinates == (1, 5) | |
assert p2.coordinates == (4, S(5)/2) | |
# test bounds | |
assert p1.bounds == (1, 5, 1, 5) | |
def test_issue_9214(): | |
p1 = Point3D(4, -2, 6) | |
p2 = Point3D(1, 2, 3) | |
p3 = Point3D(7, 2, 3) | |
assert Point3D.are_collinear(p1, p2, p3) is False | |
def test_issue_11617(): | |
p1 = Point3D(1,0,2) | |
p2 = Point2D(2,0) | |
with warns(UserWarning, test_stacklevel=False): | |
assert p1.distance(p2) == sqrt(5) | |
def test_transform(): | |
p = Point(1, 1) | |
assert p.transform(rotate(pi/2)) == Point(-1, 1) | |
assert p.transform(scale(3, 2)) == Point(3, 2) | |
assert p.transform(translate(1, 2)) == Point(2, 3) | |
assert Point(1, 1).scale(2, 3, (4, 5)) == \ | |
Point(-2, -7) | |
assert Point(1, 1).translate(4, 5) == \ | |
Point(5, 6) | |
def test_concyclic_doctest_bug(): | |
p1, p2 = Point(-1, 0), Point(1, 0) | |
p3, p4 = Point(0, 1), Point(-1, 2) | |
assert Point.is_concyclic(p1, p2, p3) | |
assert not Point.is_concyclic(p1, p2, p3, p4) | |
def test_arguments(): | |
"""Functions accepting `Point` objects in `geometry` | |
should also accept tuples and lists and | |
automatically convert them to points.""" | |
singles2d = ((1,2), [1,2], Point(1,2)) | |
singles2d2 = ((1,3), [1,3], Point(1,3)) | |
doubles2d = cartes(singles2d, singles2d2) | |
p2d = Point2D(1,2) | |
singles3d = ((1,2,3), [1,2,3], Point(1,2,3)) | |
doubles3d = subsets(singles3d, 2) | |
p3d = Point3D(1,2,3) | |
singles4d = ((1,2,3,4), [1,2,3,4], Point(1,2,3,4)) | |
doubles4d = subsets(singles4d, 2) | |
p4d = Point(1,2,3,4) | |
# test 2D | |
test_single = ['distance', 'is_scalar_multiple', 'taxicab_distance', 'midpoint', 'intersection', 'dot', 'equals', '__add__', '__sub__'] | |
test_double = ['is_concyclic', 'is_collinear'] | |
for p in singles2d: | |
Point2D(p) | |
for func in test_single: | |
for p in singles2d: | |
getattr(p2d, func)(p) | |
for func in test_double: | |
for p in doubles2d: | |
getattr(p2d, func)(*p) | |
# test 3D | |
test_double = ['is_collinear'] | |
for p in singles3d: | |
Point3D(p) | |
for func in test_single: | |
for p in singles3d: | |
getattr(p3d, func)(p) | |
for func in test_double: | |
for p in doubles3d: | |
getattr(p3d, func)(*p) | |
# test 4D | |
test_double = ['is_collinear'] | |
for p in singles4d: | |
Point(p) | |
for func in test_single: | |
for p in singles4d: | |
getattr(p4d, func)(p) | |
for func in test_double: | |
for p in doubles4d: | |
getattr(p4d, func)(*p) | |
# test evaluate=False for ops | |
x = Symbol('x') | |
a = Point(0, 1) | |
assert a + (0.1, x) == Point(0.1, 1 + x, evaluate=False) | |
a = Point(0, 1) | |
assert a/10.0 == Point(0, 0.1, evaluate=False) | |
a = Point(0, 1) | |
assert a*10.0 == Point(0.0, 10.0, evaluate=False) | |
# test evaluate=False when changing dimensions | |
u = Point(.1, .2, evaluate=False) | |
u4 = Point(u, dim=4, on_morph='ignore') | |
assert u4.args == (.1, .2, 0, 0) | |
assert all(i.is_Float for i in u4.args[:2]) | |
# and even when *not* changing dimensions | |
assert all(i.is_Float for i in Point(u).args) | |
# never raise error if creating an origin | |
assert Point(dim=3, on_morph='error') | |
# raise error with unmatched dimension | |
raises(ValueError, lambda: Point(1, 1, dim=3, on_morph='error')) | |
# test unknown on_morph | |
raises(ValueError, lambda: Point(1, 1, dim=3, on_morph='unknown')) | |
# test invalid expressions | |
raises(TypeError, lambda: Point(Basic(), Basic())) | |
def test_unit(): | |
assert Point(1, 1).unit == Point(sqrt(2)/2, sqrt(2)/2) | |
def test_dot(): | |
raises(TypeError, lambda: Point(1, 2).dot(Line((0, 0), (1, 1)))) | |
def test__normalize_dimension(): | |
assert Point._normalize_dimension(Point(1, 2), Point(3, 4)) == [ | |
Point(1, 2), Point(3, 4)] | |
assert Point._normalize_dimension( | |
Point(1, 2), Point(3, 4, 0), on_morph='ignore') == [ | |
Point(1, 2, 0), Point(3, 4, 0)] | |
def test_issue_22684(): | |
# Used to give an error | |
with evaluate(False): | |
Point(1, 2) | |
def test_direction_cosine(): | |
p1 = Point3D(0, 0, 0) | |
p2 = Point3D(1, 1, 1) | |
assert p1.direction_cosine(Point3D(1, 0, 0)) == [1, 0, 0] | |
assert p1.direction_cosine(Point3D(0, 1, 0)) == [0, 1, 0] | |
assert p1.direction_cosine(Point3D(0, 0, pi)) == [0, 0, 1] | |
assert p1.direction_cosine(Point3D(5, 0, 0)) == [1, 0, 0] | |
assert p1.direction_cosine(Point3D(0, sqrt(3), 0)) == [0, 1, 0] | |
assert p1.direction_cosine(Point3D(0, 0, 5)) == [0, 0, 1] | |
assert p1.direction_cosine(Point3D(2.4, 2.4, 0)) == [sqrt(2)/2, sqrt(2)/2, 0] | |
assert p1.direction_cosine(Point3D(1, 1, 1)) == [sqrt(3) / 3, sqrt(3) / 3, sqrt(3) / 3] | |
assert p1.direction_cosine(Point3D(-12, 0 -15)) == [-4*sqrt(41)/41, -5*sqrt(41)/41, 0] | |
assert p2.direction_cosine(Point3D(0, 0, 0)) == [-sqrt(3) / 3, -sqrt(3) / 3, -sqrt(3) / 3] | |
assert p2.direction_cosine(Point3D(1, 1, 12)) == [0, 0, 1] | |
assert p2.direction_cosine(Point3D(12, 1, 12)) == [sqrt(2) / 2, 0, sqrt(2) / 2] | |