|
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())) |
|
|
|
|
|
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)) |
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
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))) |
|
|
|
|
|
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) |
|
|
|
|
|
raises(ValueError, lambda: p3.transform(p3)) |
|
raises(ValueError, lambda: p.transform(Matrix([[1, 0], [0, 1]]))) |
|
|
|
|
|
assert 0 in Point(0, 0, 0, 0) |
|
assert 1 not in Point(0, 0, 0, 0) |
|
|
|
|
|
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) |
|
|
|
|
|
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 |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
assert Point3D(0.1, 0.2, evaluate=False, on_morph='ignore').args[0].is_Float |
|
|
|
|
|
assert p.length == 0 |
|
assert p1_1.length == 0 |
|
assert p1_2.length == 0 |
|
|
|
|
|
raises(TypeError, lambda: Point3D.are_collinear(p, x)) |
|
|
|
|
|
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) |
|
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)]) |
|
|
|
|
|
assert Point.are_coplanar(Point(x, y), Point(x, x + y), Point(y, x + 2)) is True |
|
|
|
|
|
assert planar2.intersection(Line3D(p, planar3)) == [Point3D(1, 1, 2)] |
|
|
|
|
|
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 |
|
|
|
|
|
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]]))) |
|
|
|
|
|
assert p.equals(x1) == False |
|
|
|
|
|
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(): |
|
|
|
|
|
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 |
|
|
|
|
|
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) |
|
|
|
|
|
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_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_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_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) |
|
|
|
|
|
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, 10.0, evaluate=False) |
|
|
|
|
|
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]) |
|
|
|
assert all(i.is_Float for i in Point(u).args) |
|
|
|
|
|
assert Point(dim=3, on_morph='error') |
|
|
|
|
|
raises(ValueError, lambda: Point(1, 1, dim=3, on_morph='error')) |
|
|
|
raises(ValueError, lambda: Point(1, 1, dim=3, on_morph='unknown')) |
|
|
|
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(): |
|
|
|
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] |
|
|