You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

665 lines
26 KiB

from sympy.core.numbers import (Float, Rational, oo, pi)
from sympy.core.singleton import S
from sympy.core.symbol import (Symbol, symbols)
from sympy.functions.elementary.complexes import Abs
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (acos, cos, sin)
from sympy.functions.elementary.trigonometric import tan
from sympy.geometry import (Circle, Ellipse, GeometryError, Point, Point2D,
Polygon, Ray, RegularPolygon, Segment, Triangle,
are_similar, convex_hull, intersection, Line, Ray2D)
from sympy.testing.pytest import raises, slow, warns
from sympy.core.random import verify_numerically
from sympy.geometry.polygon import rad, deg
from sympy.integrals.integrals import integrate
def feq(a, b):
"""Test if two floating point values are 'equal'."""
t_float = Float("1.0E-10")
return -t_float < a - b < t_float
@slow
def test_polygon():
x = Symbol('x', real=True)
y = Symbol('y', real=True)
q = Symbol('q', real=True)
u = Symbol('u', real=True)
v = Symbol('v', real=True)
w = Symbol('w', real=True)
x1 = Symbol('x1', real=True)
half = S.Half
a, b, c = Point(0, 0), Point(2, 0), Point(3, 3)
t = Triangle(a, b, c)
assert Polygon(Point(0, 0)) == Point(0, 0)
assert Polygon(a, Point(1, 0), b, c) == t
assert Polygon(Point(1, 0), b, c, a) == t
assert Polygon(b, c, a, Point(1, 0)) == t
# 2 "remove folded" tests
assert Polygon(a, Point(3, 0), b, c) == t
assert Polygon(a, b, Point(3, -1), b, c) == t
# remove multiple collinear points
assert Polygon(Point(-4, 15), Point(-11, 15), Point(-15, 15),
Point(-15, 33/5), Point(-15, -87/10), Point(-15, -15),
Point(-42/5, -15), Point(-2, -15), Point(7, -15), Point(15, -15),
Point(15, -3), Point(15, 10), Point(15, 15)) == \
Polygon(Point(-15, -15), Point(15, -15), Point(15, 15), Point(-15, 15))
p1 = Polygon(
Point(0, 0), Point(3, -1),
Point(6, 0), Point(4, 5),
Point(2, 3), Point(0, 3))
p2 = Polygon(
Point(6, 0), Point(3, -1),
Point(0, 0), Point(0, 3),
Point(2, 3), Point(4, 5))
p3 = Polygon(
Point(0, 0), Point(3, 0),
Point(5, 2), Point(4, 4))
p4 = Polygon(
Point(0, 0), Point(4, 4),
Point(5, 2), Point(3, 0))
p5 = Polygon(
Point(0, 0), Point(4, 4),
Point(0, 4))
p6 = Polygon(
Point(-11, 1), Point(-9, 6.6),
Point(-4, -3), Point(-8.4, -8.7))
p7 = Polygon(
Point(x, y), Point(q, u),
Point(v, w))
p8 = Polygon(
Point(x, y), Point(v, w),
Point(q, u))
p9 = Polygon(
Point(0, 0), Point(4, 4),
Point(3, 0), Point(5, 2))
p10 = Polygon(
Point(0, 2), Point(2, 2),
Point(0, 0), Point(2, 0))
p11 = Polygon(Point(0, 0), 1, n=3)
p12 = Polygon(Point(0, 0), 1, 0, n=3)
r = Ray(Point(-9, 6.6), Point(-9, 5.5))
#
# General polygon
#
assert p1 == p2
assert len(p1.args) == 6
assert len(p1.sides) == 6
assert p1.perimeter == 5 + 2*sqrt(10) + sqrt(29) + sqrt(8)
assert p1.area == 22
assert not p1.is_convex()
assert Polygon((-1, 1), (2, -1), (2, 1), (-1, -1), (3, 0)
).is_convex() is False
# ensure convex for both CW and CCW point specification
assert p3.is_convex()
assert p4.is_convex()
dict5 = p5.angles
assert dict5[Point(0, 0)] == pi / 4
assert dict5[Point(0, 4)] == pi / 2
assert p5.encloses_point(Point(x, y)) is None
assert p5.encloses_point(Point(1, 3))
assert p5.encloses_point(Point(0, 0)) is False
assert p5.encloses_point(Point(4, 0)) is False
assert p1.encloses(Circle(Point(2.5, 2.5), 5)) is False
assert p1.encloses(Ellipse(Point(2.5, 2), 5, 6)) is False
assert p5.plot_interval('x') == [x, 0, 1]
assert p5.distance(
Polygon(Point(10, 10), Point(14, 14), Point(10, 14))) == 6 * sqrt(2)
assert p5.distance(
Polygon(Point(1, 8), Point(5, 8), Point(8, 12), Point(1, 12))) == 4
with warns(UserWarning, \
match="Polygons may intersect producing erroneous output"):
Polygon(Point(0, 0), Point(1, 0), Point(1, 1)).distance(
Polygon(Point(0, 0), Point(0, 1), Point(1, 1)))
assert hash(p5) == hash(Polygon(Point(0, 0), Point(4, 4), Point(0, 4)))
assert hash(p1) == hash(p2)
assert hash(p7) == hash(p8)
assert hash(p3) != hash(p9)
assert p5 == Polygon(Point(4, 4), Point(0, 4), Point(0, 0))
assert Polygon(Point(4, 4), Point(0, 4), Point(0, 0)) in p5
assert p5 != Point(0, 4)
assert Point(0, 1) in p5
assert p5.arbitrary_point('t').subs(Symbol('t', real=True), 0) == \
Point(0, 0)
raises(ValueError, lambda: Polygon(
Point(x, 0), Point(0, y), Point(x, y)).arbitrary_point('x'))
assert p6.intersection(r) == [Point(-9, Rational(-84, 13)), Point(-9, Rational(33, 5))]
assert p10.area == 0
assert p11 == RegularPolygon(Point(0, 0), 1, 3, 0)
assert p11 == p12
assert p11.vertices[0] == Point(1, 0)
assert p11.args[0] == Point(0, 0)
p11.spin(pi/2)
assert p11.vertices[0] == Point(0, 1)
#
# Regular polygon
#
p1 = RegularPolygon(Point(0, 0), 10, 5)
p2 = RegularPolygon(Point(0, 0), 5, 5)
raises(GeometryError, lambda: RegularPolygon(Point(0, 0), Point(0,
1), Point(1, 1)))
raises(GeometryError, lambda: RegularPolygon(Point(0, 0), 1, 2))
raises(ValueError, lambda: RegularPolygon(Point(0, 0), 1, 2.5))
assert p1 != p2
assert p1.interior_angle == pi*Rational(3, 5)
assert p1.exterior_angle == pi*Rational(2, 5)
assert p2.apothem == 5*cos(pi/5)
assert p2.circumcenter == p1.circumcenter == Point(0, 0)
assert p1.circumradius == p1.radius == 10
assert p2.circumcircle == Circle(Point(0, 0), 5)
assert p2.incircle == Circle(Point(0, 0), p2.apothem)
assert p2.inradius == p2.apothem == (5 * (1 + sqrt(5)) / 4)
p2.spin(pi / 10)
dict1 = p2.angles
assert dict1[Point(0, 5)] == 3 * pi / 5
assert p1.is_convex()
assert p1.rotation == 0
assert p1.encloses_point(Point(0, 0))
assert p1.encloses_point(Point(11, 0)) is False
assert p2.encloses_point(Point(0, 4.9))
p1.spin(pi/3)
assert p1.rotation == pi/3
assert p1.vertices[0] == Point(5, 5*sqrt(3))
for var in p1.args:
if isinstance(var, Point):
assert var == Point(0, 0)
else:
assert var in (5, 10, pi / 3)
assert p1 != Point(0, 0)
assert p1 != p5
# while spin works in place (notice that rotation is 2pi/3 below)
# rotate returns a new object
p1_old = p1
assert p1.rotate(pi/3) == RegularPolygon(Point(0, 0), 10, 5, pi*Rational(2, 3))
assert p1 == p1_old
assert p1.area == (-250*sqrt(5) + 1250)/(4*tan(pi/5))
assert p1.length == 20*sqrt(-sqrt(5)/8 + Rational(5, 8))
assert p1.scale(2, 2) == \
RegularPolygon(p1.center, p1.radius*2, p1._n, p1.rotation)
assert RegularPolygon((0, 0), 1, 4).scale(2, 3) == \
Polygon(Point(2, 0), Point(0, 3), Point(-2, 0), Point(0, -3))
assert repr(p1) == str(p1)
#
# Angles
#
angles = p4.angles
assert feq(angles[Point(0, 0)].evalf(), Float("0.7853981633974483"))
assert feq(angles[Point(4, 4)].evalf(), Float("1.2490457723982544"))
assert feq(angles[Point(5, 2)].evalf(), Float("1.8925468811915388"))
assert feq(angles[Point(3, 0)].evalf(), Float("2.3561944901923449"))
angles = p3.angles
assert feq(angles[Point(0, 0)].evalf(), Float("0.7853981633974483"))
assert feq(angles[Point(4, 4)].evalf(), Float("1.2490457723982544"))
assert feq(angles[Point(5, 2)].evalf(), Float("1.8925468811915388"))
assert feq(angles[Point(3, 0)].evalf(), Float("2.3561944901923449"))
#
# Triangle
#
p1 = Point(0, 0)
p2 = Point(5, 0)
p3 = Point(0, 5)
t1 = Triangle(p1, p2, p3)
t2 = Triangle(p1, p2, Point(Rational(5, 2), sqrt(Rational(75, 4))))
t3 = Triangle(p1, Point(x1, 0), Point(0, x1))
s1 = t1.sides
assert Triangle(p1, p2, p1) == Polygon(p1, p2, p1) == Segment(p1, p2)
raises(GeometryError, lambda: Triangle(Point(0, 0)))
# Basic stuff
assert Triangle(p1, p1, p1) == p1
assert Triangle(p2, p2*2, p2*3) == Segment(p2, p2*3)
assert t1.area == Rational(25, 2)
assert t1.is_right()
assert t2.is_right() is False
assert t3.is_right()
assert p1 in t1
assert t1.sides[0] in t1
assert Segment((0, 0), (1, 0)) in t1
assert Point(5, 5) not in t2
assert t1.is_convex()
assert feq(t1.angles[p1].evalf(), pi.evalf()/2)
assert t1.is_equilateral() is False
assert t2.is_equilateral()
assert t3.is_equilateral() is False
assert are_similar(t1, t2) is False
assert are_similar(t1, t3)
assert are_similar(t2, t3) is False
assert t1.is_similar(Point(0, 0)) is False
assert t1.is_similar(t2) is False
# Bisectors
bisectors = t1.bisectors()
assert bisectors[p1] == Segment(
p1, Point(Rational(5, 2), Rational(5, 2)))
assert t2.bisectors()[p2] == Segment(
Point(5, 0), Point(Rational(5, 4), 5*sqrt(3)/4))
p4 = Point(0, x1)
assert t3.bisectors()[p4] == Segment(p4, Point(x1*(sqrt(2) - 1), 0))
ic = (250 - 125*sqrt(2))/50
assert t1.incenter == Point(ic, ic)
# Inradius
assert t1.inradius == t1.incircle.radius == 5 - 5*sqrt(2)/2
assert t2.inradius == t2.incircle.radius == 5*sqrt(3)/6
assert t3.inradius == t3.incircle.radius == x1**2/((2 + sqrt(2))*Abs(x1))
# Exradius
assert t1.exradii[t1.sides[2]] == 5*sqrt(2)/2
# Excenters
assert t1.excenters[t1.sides[2]] == Point2D(25*sqrt(2), -5*sqrt(2)/2)
# Circumcircle
assert t1.circumcircle.center == Point(2.5, 2.5)
# Medians + Centroid
m = t1.medians
assert t1.centroid == Point(Rational(5, 3), Rational(5, 3))
assert m[p1] == Segment(p1, Point(Rational(5, 2), Rational(5, 2)))
assert t3.medians[p1] == Segment(p1, Point(x1/2, x1/2))
assert intersection(m[p1], m[p2], m[p3]) == [t1.centroid]
assert t1.medial == Triangle(Point(2.5, 0), Point(0, 2.5), Point(2.5, 2.5))
# Nine-point circle
assert t1.nine_point_circle == Circle(Point(2.5, 0),
Point(0, 2.5), Point(2.5, 2.5))
assert t1.nine_point_circle == Circle(Point(0, 0),
Point(0, 2.5), Point(2.5, 2.5))
# Perpendicular
altitudes = t1.altitudes
assert altitudes[p1] == Segment(p1, Point(Rational(5, 2), Rational(5, 2)))
assert altitudes[p2].equals(s1[0])
assert altitudes[p3] == s1[2]
assert t1.orthocenter == p1
t = S('''Triangle(
Point(100080156402737/5000000000000, 79782624633431/500000000000),
Point(39223884078253/2000000000000, 156345163124289/1000000000000),
Point(31241359188437/1250000000000, 338338270939941/1000000000000000))''')
assert t.orthocenter == S('''Point(-780660869050599840216997'''
'''79471538701955848721853/80368430960602242240789074233100000000000000,'''
'''20151573611150265741278060334545897615974257/16073686192120448448157'''
'''8148466200000000000)''')
# Ensure
assert len(intersection(*bisectors.values())) == 1
assert len(intersection(*altitudes.values())) == 1
assert len(intersection(*m.values())) == 1
# Distance
p1 = Polygon(
Point(0, 0), Point(1, 0),
Point(1, 1), Point(0, 1))
p2 = Polygon(
Point(0, Rational(5)/4), Point(1, Rational(5)/4),
Point(1, Rational(9)/4), Point(0, Rational(9)/4))
p3 = Polygon(
Point(1, 2), Point(2, 2),
Point(2, 1))
p4 = Polygon(
Point(1, 1), Point(Rational(6)/5, 1),
Point(1, Rational(6)/5))
pt1 = Point(half, half)
pt2 = Point(1, 1)
'''Polygon to Point'''
assert p1.distance(pt1) == half
assert p1.distance(pt2) == 0
assert p2.distance(pt1) == Rational(3)/4
assert p3.distance(pt2) == sqrt(2)/2
'''Polygon to Polygon'''
# p1.distance(p2) emits a warning
with warns(UserWarning, \
match="Polygons may intersect producing erroneous output"):
assert p1.distance(p2) == half/2
assert p1.distance(p3) == sqrt(2)/2
# p3.distance(p4) emits a warning
with warns(UserWarning, \
match="Polygons may intersect producing erroneous output"):
assert p3.distance(p4) == (sqrt(2)/2 - sqrt(Rational(2)/25)/2)
def test_convex_hull():
p = [Point(-5, -1), Point(-2, 1), Point(-2, -1), Point(-1, -3), \
Point(0, 0), Point(1, 1), Point(2, 2), Point(2, -1), Point(3, 1), \
Point(4, -1), Point(6, 2)]
ch = Polygon(p[0], p[3], p[9], p[10], p[6], p[1])
#test handling of duplicate points
p.append(p[3])
#more than 3 collinear points
another_p = [Point(-45, -85), Point(-45, 85), Point(-45, 26), \
Point(-45, -24)]
ch2 = Segment(another_p[0], another_p[1])
assert convex_hull(*another_p) == ch2
assert convex_hull(*p) == ch
assert convex_hull(p[0]) == p[0]
assert convex_hull(p[0], p[1]) == Segment(p[0], p[1])
# no unique points
assert convex_hull(*[p[-1]]*3) == p[-1]
# collection of items
assert convex_hull(*[Point(0, 0), \
Segment(Point(1, 0), Point(1, 1)), \
RegularPolygon(Point(2, 0), 2, 4)]) == \
Polygon(Point(0, 0), Point(2, -2), Point(4, 0), Point(2, 2))
def test_encloses():
# square with a dimpled left side
s = Polygon(Point(0, 0), Point(1, 0), Point(1, 1), Point(0, 1), \
Point(S.Half, S.Half))
# the following is True if the polygon isn't treated as closing on itself
assert s.encloses(Point(0, S.Half)) is False
assert s.encloses(Point(S.Half, S.Half)) is False # it's a vertex
assert s.encloses(Point(Rational(3, 4), S.Half)) is True
def test_triangle_kwargs():
assert Triangle(sss=(3, 4, 5)) == \
Triangle(Point(0, 0), Point(3, 0), Point(3, 4))
assert Triangle(asa=(30, 2, 30)) == \
Triangle(Point(0, 0), Point(2, 0), Point(1, sqrt(3)/3))
assert Triangle(sas=(1, 45, 2)) == \
Triangle(Point(0, 0), Point(2, 0), Point(sqrt(2)/2, sqrt(2)/2))
assert Triangle(sss=(1, 2, 5)) is None
assert deg(rad(180)) == 180
def test_transform():
pts = [Point(0, 0), Point(S.Half, Rational(1, 4)), Point(1, 1)]
pts_out = [Point(-4, -10), Point(-3, Rational(-37, 4)), Point(-2, -7)]
assert Triangle(*pts).scale(2, 3, (4, 5)) == Triangle(*pts_out)
assert RegularPolygon((0, 0), 1, 4).scale(2, 3, (4, 5)) == \
Polygon(Point(-2, -10), Point(-4, -7), Point(-6, -10), Point(-4, -13))
# Checks for symmetric scaling
assert RegularPolygon((0, 0), 1, 4).scale(2, 2) == \
RegularPolygon(Point2D(0, 0), 2, 4, 0)
def test_reflect():
x = Symbol('x', real=True)
y = Symbol('y', real=True)
b = Symbol('b')
m = Symbol('m')
l = Line((0, b), slope=m)
p = Point(x, y)
r = p.reflect(l)
dp = l.perpendicular_segment(p).length
dr = l.perpendicular_segment(r).length
assert verify_numerically(dp, dr)
assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((3, 0), slope=oo)) \
== Triangle(Point(5, 0), Point(4, 0), Point(4, 2))
assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((0, 3), slope=oo)) \
== Triangle(Point(-1, 0), Point(-2, 0), Point(-2, 2))
assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((0, 3), slope=0)) \
== Triangle(Point(1, 6), Point(2, 6), Point(2, 4))
assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((3, 0), slope=0)) \
== Triangle(Point(1, 0), Point(2, 0), Point(2, -2))
def test_bisectors():
p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1)
p = Polygon(Point(0, 0), Point(2, 0), Point(1, 1), Point(0, 3))
q = Polygon(Point(1, 0), Point(2, 0), Point(3, 3), Point(-1, 5))
poly = Polygon(Point(3, 4), Point(0, 0), Point(8, 7), Point(-1, 1), Point(19, -19))
t = Triangle(p1, p2, p3)
assert t.bisectors()[p2] == Segment(Point(1, 0), Point(0, sqrt(2) - 1))
assert p.bisectors()[Point2D(0, 3)] == Ray2D(Point2D(0, 3), \
Point2D(sin(acos(2*sqrt(5)/5)/2), 3 - cos(acos(2*sqrt(5)/5)/2)))
assert q.bisectors()[Point2D(-1, 5)] == \
Ray2D(Point2D(-1, 5), Point2D(-1 + sqrt(29)*(5*sin(acos(9*sqrt(145)/145)/2) + \
2*cos(acos(9*sqrt(145)/145)/2))/29, sqrt(29)*(-5*cos(acos(9*sqrt(145)/145)/2) + \
2*sin(acos(9*sqrt(145)/145)/2))/29 + 5))
assert poly.bisectors()[Point2D(-1, 1)] == Ray2D(Point2D(-1, 1), \
Point2D(-1 + sin(acos(sqrt(26)/26)/2 + pi/4), 1 - sin(-acos(sqrt(26)/26)/2 + pi/4)))
def test_incenter():
assert Triangle(Point(0, 0), Point(1, 0), Point(0, 1)).incenter \
== Point(1 - sqrt(2)/2, 1 - sqrt(2)/2)
def test_inradius():
assert Triangle(Point(0, 0), Point(4, 0), Point(0, 3)).inradius == 1
def test_incircle():
assert Triangle(Point(0, 0), Point(2, 0), Point(0, 2)).incircle \
== Circle(Point(2 - sqrt(2), 2 - sqrt(2)), 2 - sqrt(2))
def test_exradii():
t = Triangle(Point(0, 0), Point(6, 0), Point(0, 2))
assert t.exradii[t.sides[2]] == (-2 + sqrt(10))
def test_medians():
t = Triangle(Point(0, 0), Point(1, 0), Point(0, 1))
assert t.medians[Point(0, 0)] == Segment(Point(0, 0), Point(S.Half, S.Half))
def test_medial():
assert Triangle(Point(0, 0), Point(1, 0), Point(0, 1)).medial \
== Triangle(Point(S.Half, 0), Point(S.Half, S.Half), Point(0, S.Half))
def test_nine_point_circle():
assert Triangle(Point(0, 0), Point(1, 0), Point(0, 1)).nine_point_circle \
== Circle(Point2D(Rational(1, 4), Rational(1, 4)), sqrt(2)/4)
def test_eulerline():
assert Triangle(Point(0, 0), Point(1, 0), Point(0, 1)).eulerline \
== Line(Point2D(0, 0), Point2D(S.Half, S.Half))
assert Triangle(Point(0, 0), Point(10, 0), Point(5, 5*sqrt(3))).eulerline \
== Point2D(5, 5*sqrt(3)/3)
assert Triangle(Point(4, -6), Point(4, -1), Point(-3, 3)).eulerline \
== Line(Point2D(Rational(64, 7), 3), Point2D(Rational(-29, 14), Rational(-7, 2)))
def test_intersection():
poly1 = Triangle(Point(0, 0), Point(1, 0), Point(0, 1))
poly2 = Polygon(Point(0, 1), Point(-5, 0),
Point(0, -4), Point(0, Rational(1, 5)),
Point(S.Half, -0.1), Point(1, 0), Point(0, 1))
assert poly1.intersection(poly2) == [Point2D(Rational(1, 3), 0),
Segment(Point(0, Rational(1, 5)), Point(0, 0)),
Segment(Point(1, 0), Point(0, 1))]
assert poly2.intersection(poly1) == [Point(Rational(1, 3), 0),
Segment(Point(0, 0), Point(0, Rational(1, 5))),
Segment(Point(1, 0), Point(0, 1))]
assert poly1.intersection(Point(0, 0)) == [Point(0, 0)]
assert poly1.intersection(Point(-12, -43)) == []
assert poly2.intersection(Line((-12, 0), (12, 0))) == [Point(-5, 0),
Point(0, 0), Point(Rational(1, 3), 0), Point(1, 0)]
assert poly2.intersection(Line((-12, 12), (12, 12))) == []
assert poly2.intersection(Ray((-3, 4), (1, 0))) == [Segment(Point(1, 0),
Point(0, 1))]
assert poly2.intersection(Circle((0, -1), 1)) == [Point(0, -2),
Point(0, 0)]
assert poly1.intersection(poly1) == [Segment(Point(0, 0), Point(1, 0)),
Segment(Point(0, 1), Point(0, 0)), Segment(Point(1, 0), Point(0, 1))]
assert poly2.intersection(poly2) == [Segment(Point(-5, 0), Point(0, -4)),
Segment(Point(0, -4), Point(0, Rational(1, 5))),
Segment(Point(0, Rational(1, 5)), Point(S.Half, Rational(-1, 10))),
Segment(Point(0, 1), Point(-5, 0)),
Segment(Point(S.Half, Rational(-1, 10)), Point(1, 0)),
Segment(Point(1, 0), Point(0, 1))]
assert poly2.intersection(Triangle(Point(0, 1), Point(1, 0), Point(-1, 1))) \
== [Point(Rational(-5, 7), Rational(6, 7)), Segment(Point2D(0, 1), Point(1, 0))]
assert poly1.intersection(RegularPolygon((-12, -15), 3, 3)) == []
def test_parameter_value():
t = Symbol('t')
sq = Polygon((0, 0), (0, 1), (1, 1), (1, 0))
assert sq.parameter_value((0.5, 1), t) == {t: Rational(3, 8)}
q = Polygon((0, 0), (2, 1), (2, 4), (4, 0))
assert q.parameter_value((4, 0), t) == {t: -6 + 3*sqrt(5)} # ~= 0.708
raises(ValueError, lambda: sq.parameter_value((5, 6), t))
raises(ValueError, lambda: sq.parameter_value(Circle(Point(0, 0), 1), t))
def test_issue_12966():
poly = Polygon(Point(0, 0), Point(0, 10), Point(5, 10), Point(5, 5),
Point(10, 5), Point(10, 0))
t = Symbol('t')
pt = poly.arbitrary_point(t)
DELTA = 5/poly.perimeter
assert [pt.subs(t, DELTA*i) for i in range(int(1/DELTA))] == [
Point(0, 0), Point(0, 5), Point(0, 10), Point(5, 10),
Point(5, 5), Point(10, 5), Point(10, 0), Point(5, 0)]
def test_second_moment_of_area():
x, y = symbols('x, y')
# triangle
p1, p2, p3 = [(0, 0), (4, 0), (0, 2)]
p = (0, 0)
# equation of hypotenuse
eq_y = (1-x/4)*2
I_yy = integrate((x**2) * (integrate(1, (y, 0, eq_y))), (x, 0, 4))
I_xx = integrate(1 * (integrate(y**2, (y, 0, eq_y))), (x, 0, 4))
I_xy = integrate(x * (integrate(y, (y, 0, eq_y))), (x, 0, 4))
triangle = Polygon(p1, p2, p3)
assert (I_xx - triangle.second_moment_of_area(p)[0]) == 0
assert (I_yy - triangle.second_moment_of_area(p)[1]) == 0
assert (I_xy - triangle.second_moment_of_area(p)[2]) == 0
# rectangle
p1, p2, p3, p4=[(0, 0), (4, 0), (4, 2), (0, 2)]
I_yy = integrate((x**2) * integrate(1, (y, 0, 2)), (x, 0, 4))
I_xx = integrate(1 * integrate(y**2, (y, 0, 2)), (x, 0, 4))
I_xy = integrate(x * integrate(y, (y, 0, 2)), (x, 0, 4))
rectangle = Polygon(p1, p2, p3, p4)
assert (I_xx - rectangle.second_moment_of_area(p)[0]) == 0
assert (I_yy - rectangle.second_moment_of_area(p)[1]) == 0
assert (I_xy - rectangle.second_moment_of_area(p)[2]) == 0
r = RegularPolygon(Point(0, 0), 5, 3)
assert r.second_moment_of_area() == (1875*sqrt(3)/S(32), 1875*sqrt(3)/S(32), 0)
def test_first_moment():
a, b = symbols('a, b', positive=True)
# rectangle
p1 = Polygon((0, 0), (a, 0), (a, b), (0, b))
assert p1.first_moment_of_area() == (a*b**2/8, a**2*b/8)
assert p1.first_moment_of_area((a/3, b/4)) == (-3*a*b**2/32, -a**2*b/9)
p1 = Polygon((0, 0), (40, 0), (40, 30), (0, 30))
assert p1.first_moment_of_area() == (4500, 6000)
# triangle
p2 = Polygon((0, 0), (a, 0), (a/2, b))
assert p2.first_moment_of_area() == (4*a*b**2/81, a**2*b/24)
assert p2.first_moment_of_area((a/8, b/6)) == (-25*a*b**2/648, -5*a**2*b/768)
p2 = Polygon((0, 0), (12, 0), (12, 30))
assert p2.first_moment_of_area() == (S(1600)/3, -S(640)/3)
def test_section_modulus_and_polar_second_moment_of_area():
a, b = symbols('a, b', positive=True)
x, y = symbols('x, y')
rectangle = Polygon((0, b), (0, 0), (a, 0), (a, b))
assert rectangle.section_modulus(Point(x, y)) == (a*b**3/12/(-b/2 + y), a**3*b/12/(-a/2 + x))
assert rectangle.polar_second_moment_of_area() == a**3*b/12 + a*b**3/12
convex = RegularPolygon((0, 0), 1, 6)
assert convex.section_modulus() == (Rational(5, 8), sqrt(3)*Rational(5, 16))
assert convex.polar_second_moment_of_area() == 5*sqrt(3)/S(8)
concave = Polygon((0, 0), (1, 8), (3, 4), (4, 6), (7, 1))
assert concave.section_modulus() == (Rational(-6371, 429), Rational(-9778, 519))
assert concave.polar_second_moment_of_area() == Rational(-38669, 252)
def test_cut_section():
# concave polygon
p = Polygon((-1, -1), (1, Rational(5, 2)), (2, 1), (3, Rational(5, 2)), (4, 2), (5, 3), (-1, 3))
l = Line((0, 0), (Rational(9, 2), 3))
p1 = p.cut_section(l)[0]
p2 = p.cut_section(l)[1]
assert p1 == Polygon(
Point2D(Rational(-9, 13), Rational(-6, 13)), Point2D(1, Rational(5, 2)), Point2D(Rational(24, 13), Rational(16, 13)),
Point2D(Rational(12, 5), Rational(8, 5)), Point2D(3, Rational(5, 2)), Point2D(Rational(24, 7), Rational(16, 7)),
Point2D(Rational(9, 2), 3), Point2D(-1, 3), Point2D(-1, Rational(-2, 3)))
assert p2 == Polygon(Point2D(-1, -1), Point2D(Rational(-9, 13), Rational(-6, 13)), Point2D(Rational(24, 13), Rational(16, 13)),
Point2D(2, 1), Point2D(Rational(12, 5), Rational(8, 5)), Point2D(Rational(24, 7), Rational(16, 7)), Point2D(4, 2), Point2D(5, 3),
Point2D(Rational(9, 2), 3), Point2D(-1, Rational(-2, 3)))
# convex polygon
p = RegularPolygon(Point2D(0, 0), 6, 6)
s = p.cut_section(Line((0, 0), slope=1))
assert s[0] == Polygon(Point2D(-3*sqrt(3) + 9, -3*sqrt(3) + 9), Point2D(3, 3*sqrt(3)),
Point2D(-3, 3*sqrt(3)), Point2D(-6, 0), Point2D(-9 + 3*sqrt(3), -9 + 3*sqrt(3)))
assert s[1] == Polygon(Point2D(6, 0), Point2D(-3*sqrt(3) + 9, -3*sqrt(3) + 9),
Point2D(-9 + 3*sqrt(3), -9 + 3*sqrt(3)), Point2D(-3, -3*sqrt(3)), Point2D(3, -3*sqrt(3)))
# case where line does not intersects but coincides with the edge of polygon
a, b = 20, 10
t1, t2, t3, t4 = [(0, b), (0, 0), (a, 0), (a, b)]
p = Polygon(t1, t2, t3, t4)
p1, p2 = p.cut_section(Line((0, b), slope=0))
assert p1 == None
assert p2 == Polygon(Point2D(0, 10), Point2D(0, 0), Point2D(20, 0), Point2D(20, 10))
p3, p4 = p.cut_section(Line((0, 0), slope=0))
assert p3 == Polygon(Point2D(0, 10), Point2D(0, 0), Point2D(20, 0), Point2D(20, 10))
assert p4 == None
# case where the line does not intersect with a polygon at all
raises(ValueError, lambda: p.cut_section(Line((0, a), slope=0)))
def test_type_of_triangle():
# Isoceles triangle
p1 = Polygon(Point(0, 0), Point(5, 0), Point(2, 4))
assert p1.is_isosceles() == True
assert p1.is_scalene() == False
assert p1.is_equilateral() == False
# Scalene triangle
p2 = Polygon (Point(0, 0), Point(0, 2), Point(4, 0))
assert p2.is_isosceles() == False
assert p2.is_scalene() == True
assert p2.is_equilateral() == False
# Equilateral triagle
p3 = Polygon(Point(0, 0), Point(6, 0), Point(3, sqrt(27)))
assert p3.is_isosceles() == True
assert p3.is_scalene() == False
assert p3.is_equilateral() == True
def test_do_poly_distance():
# Non-intersecting polygons
square1 = Polygon (Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0))
triangle1 = Polygon(Point(1, 2), Point(2, 2), Point(2, 1))
assert square1._do_poly_distance(triangle1) == sqrt(2)/2
# Polygons which sides intersect
square2 = Polygon(Point(1, 0), Point(2, 0), Point(2, 1), Point(1, 1))
with warns(UserWarning, \
match="Polygons may intersect producing erroneous output", test_stacklevel=False):
assert square1._do_poly_distance(square2) == 0
# Polygons which bodies intersect
triangle2 = Polygon(Point(0, -1), Point(2, -1), Point(S.Half, S.Half))
with warns(UserWarning, \
match="Polygons may intersect producing erroneous output", test_stacklevel=False):
assert triangle2._do_poly_distance(square1) == 0