polygon

Polygons embedded in the plane \(\mathbb{R}^2\).

The emphasis is mostly on convex polygons but there is some limited support for non-convex polygons.

EXAMPLES:

sage: from flatsurf.geometry.polygon import Polygon

sage: K.<sqrt2> = NumberField(x^2 - 2, embedding=AA(2).sqrt())
sage: p = Polygon(edges=[(1,0), (-sqrt2,1+sqrt2), (sqrt2-1,-1-sqrt2)])
sage: p
Polygon(vertices=[(0, 0), (1, 0), (-sqrt2 + 1, sqrt2 + 1)])

sage: M = MatrixSpace(K,2)
sage: m = M([[1,1+sqrt2],[0,1]])
sage: m * p
Polygon(vertices=[(0, 0), (1, 0), (sqrt2 + 4, sqrt2 + 1)])
flatsurf.geometry.polygon.ConvexPolygons(base_ring)[source]

EXAMPLES:

sage: from flatsurf import ConvexPolygons
sage: P = ConvexPolygons(QQ)
doctest:warning
...
UserWarning: ConvexPolygons() has been deprecated and will be removed from a future version of sage-flatsurf; use Polygon() to create polygons.
If you really need the category of convex polygons over a ring use EuclideanPolygons(ring).Simple().Convex() instead.
sage: P(vertices=[(0, 0), (1, 0), (0, 1)])
doctest:warning
...
UserWarning: ConvexPolygons(…)(…) has been deprecated and will be removed in a future version of sage-flatsurf; use Polygon() instead
Polygon(vertices=[(0, 0), (1, 0), (0, 1)])
flatsurf.geometry.polygon.EquiangularPolygons(*angles, **kwds)[source]

EXAMPLES:

sage: from flatsurf import EquiangularPolygons
sage: EquiangularPolygons(1, 1, 1)
doctest:warning
...
UserWarning: EquiangularPolygons() has been deprecated and will be removed in a future version of sage-flatsurf; use EuclideanPolygonsWithAngles() instead
Category of simple euclidean equilateral triangles over Number Field in c with defining polynomial x^2 - 3 with c = 1.732050807568878?
class flatsurf.geometry.polygon.EuclideanPolygon(base_ring, vertices, category=None)[source]

A (possibly non-convex) simple polygon in the plane \(\mathbb{R}^2\).

EXAMPLES:

sage: from flatsurf import polygons, Polygon
sage: s = polygons.square()
sage: s
Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)])

sage: Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)])
Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)])
Element

alias of EuclideanPolygonPoint

change_ring(ring)[source]

Return a copy of this polygon whose vertices have coordinates over the base ring ring.

EXAMPLES:

sage: from flatsurf import polygons
sage: S = polygons.square()
sage: K.<sqrt2> = NumberField(x^2 - 2, embedding=AA(2)**(1/2))
sage: S.change_ring(K)
Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)])
sage: S.change_ring(K).base_ring()
Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.4142...
cmp(other)[source]

Implement a total order on polygons

is_strictly_convex()[source]

Return whether this polygon is strictly convex.

EXAMPLES:

sage: from flatsurf import Polygon
sage: Polygon(vertices=[(0,0), (1,0), (1,1)]).is_strictly_convex()
doctest:warning
...
UserWarning: is_strictly_convex() has been deprecated and will be removed in a future version of sage-flatsurf; use is_convex(strict=True) instead
True
sage: Polygon(vertices=[(0,0), (1,0), (2,0), (1,1)]).is_strictly_convex()
False
num_edges()[source]

Return the number of edges of this polygon.

EXAMPLES:

sage: from flatsurf import polygons
sage: S = polygons.square()
sage: S.num_edges()
doctest:warning
...
UserWarning: num_edges() has been deprecated and will be removed in a future version of sage-flatsurf; use len(vertices()) instead
4
parent()[source]

Return the category this polygon belongs to.

EXAMPLES:

sage: from flatsurf import polygons
sage: s = polygons.square()
sage: s.parent()
doctest:warning
...
UserWarning: parent() of a polygon has been deprecated and will be removed in a future version of sage-flatsurf; use category() instead
Category of convex simple euclidean rectangles over Rational Field

Note that the parent may change during the lifetime of a polygon as more of its features are discovered:

sage: from flatsurf import Polygon
sage: p = Polygon(vertices=[(0, 0), (1, 0), (1, 1)])
sage: p.parent()
Category of convex simple euclidean polygons over Rational Field
sage: p.angles()
(1/8, 1/4, 1/8)
sage: p.parent()
Category of convex simple euclidean triangles with angles (1/8, 1/4, 1/8) over Rational Field
translate(u)[source]

Return a copy of this polygon that has been translated by u.

vertices(translation=None, marked_vertices=True)[source]

Return the vertices of this polygon in counterclockwise order as vectors in the real plane.

INPUT:

  • marked_vertices – a boolean (default: True); whether to include vertices with a π angle in the output.

EXAMPLES:

sage: from flatsurf import polygons
sage: s = polygons.square()
sage: s.vertices()
((0, 0), (1, 0), (1, 1), (0, 1))
class flatsurf.geometry.polygon.EuclideanPolygonPoint(parent, xy)[source]

A point in a polygon.

EXAMPLES:

sage: from flatsurf import polygons
sage: s = polygons.square()

sage: s.an_element()
(0, 0)
position()[source]

Describe the position of this point in the polygon.

OUTPUT:

A PolygonPosition object.

EXAMPLES:

sage: from flatsurf import polygons
sage: s = polygons.square()

sage: p = s.an_element()
sage: p
(0, 0)

sage: p.position()
point positioned on vertex 0 of polygon
flatsurf.geometry.polygon.EuclideanPolygonsWithAngles(*angles)[source]

Return the category of Euclidean polygons with prescribed angles over a (minimal) number field.

This method is a convenience to interact with that category. To create polygons with prescribed angles over such a field, one should just use Polygon() directly, see below.

INPUT:

  • angles – a sequence of integers or rationals describing the angles of the polygon (the number get normalized so that they sum to (n-2)π automatically.

flatsurf.geometry.polygon.Polygon(vertices, edges, angles, lengths, base_ring, category, check, *args, **kwds)[source]

Return a polygon from the given vertices, edges, or angles.

INPUT:

  • vertices – a sequence of vertices or None (default: None); the vertices of the polygon as points in the real plane

  • edges – a sequence of vectors or None (default: None); the vectors connecting the vertices of the polygon

  • angles – a sequence of numbers that prescribe the inner angles of the polygon or None (default: None); the angles are rescaled so that their sum matches the sum of the angles in an ngon.

  • lengths – a sequence of numbers that prescribe the lengths of the edges of the polygon or None (default: None)

  • base_ring – a ring or None (default: None); the ring over which the polygon will be defined

  • category – a category or None (default: None); the category the polygon will be in (further refined from the features of the polygon that are found during the construction.)

  • check – a boolean (default: True); whether to check the consistency of the parameters or blindly trust them. Setting this to False allows creation of degenerate polygons in some cases. While they might be somewhat functional, no guarantees are made about such polygons.

EXAMPLES:

A right triangle:

sage: from flatsurf import Polygon
sage: Polygon(vertices=[(0, 0), (1, 0), (0, 1)])
Polygon(vertices=[(0, 0), (1, 0), (0, 1)])

A right triangle that is not based at the origin:

sage: Polygon(vertices=[(1, 0), (2, 0), (1, 1)])
Polygon(vertices=[(1, 0), (2, 0), (1, 1)])

A right triangle at the origin, specified by giving the edge vectors:

sage: Polygon(edges=[(1, 0), (-1, 1), (0, -1)])
Polygon(vertices=[(0, 0), (1, 0), (0, 1)])

When redundant information is given, it is checked for consistency:

sage: Polygon(vertices=[(0, 0), (1, 0), (0, 1)], edges=[(1, 0), (-1, 1), (0, -1)])
Polygon(vertices=[(0, 0), (1, 0), (0, 1)])
sage: Polygon(vertices=[(1, 0), (2, 0), (1, 1)], edges=[(1, 0), (-1, 1), (0, -1)])
Polygon(vertices=[(1, 0), (2, 0), (1, 1)])
sage: Polygon(vertices=[(0, 0), (2, 0), (1, 1)], edges=[(1, 0), (-1, 1), (0, -1)])
Traceback (most recent call last):
...
ValueError: vertices and edges are not compatible

Polygons given by edges must be closed (in particular we do not add an edge automatically to close things up since this is often not what the user wanted):

sage: Polygon(edges=[(1, 0), (0, 1), (1, 1)])
Traceback (most recent call last):
...
ValueError: polygon not closed

A polygon with prescribed angles:

sage: Polygon(angles=[2, 1, 1])
Polygon(vertices=[(0, 0), (1, 0), (0, 1)])

Again, if vertices and edges are also specified, they must be compatible with the angles:

sage: Polygon(angles=[2, 1, 1], vertices=[(0, 0), (1, 0), (0, 1)], edges=[(1, 0), (-1, 1), (0, -1)])
Polygon(vertices=[(0, 0), (1, 0), (0, 1)])

sage: Polygon(angles=[1, 2, 3], vertices=[(0, 0), (1, 0), (0, 1)], edges=[(1, 0), (-1, 1), (0, -1)])
Traceback (most recent call last):
...
ValueError: polygon does not have the prescribed angles

When angles are specified, side lengths can also be prescribed:

sage: Polygon(angles=[1, 1, 1], lengths=[1, 1, 1])
Polygon(vertices=[(0, 0), (1, 0), (1/2, 1/2*c)])

The function will deduce lengths if one or two are missing:

sage: Polygon(angles=[1, 1, 1, 1], lengths=[1, 1, 1])
Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)])

sage: Polygon(angles=[1, 1, 1, 1], lengths=[1, 1])
Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)])

sage: Polygon(angles=[1, 1, 1, 1], lengths=[1])
Traceback (most recent call last):
...
NotImplementedError: cannot construct a quadrilateral from 4 angles and 2 vertices

Equally, we deduce vertices or edges:

sage: Polygon(angles=[1, 1, 1, 1], vertices=[(0, 0), (1, 0), (1, 1)])
Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)])

sage: Polygon(angles=[1, 1, 1, 1], edges=[(1, 0), (0, 1)])
Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)])

When the angles are incompatible with the data, an error is reported (that might be somewhat cryptic at times):

sage: Polygon(angles=[1, 1, 1, 1], edges=[(1, 0), (0, 1), (1, 2)])
Traceback (most recent call last):
...
NotImplementedError: cannot recover a rational angle from these numerical results

When lengths are given in addition to vertices or edges, they are checked for consistency:

sage: Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)], lengths=[1, 1, 1, 1])
Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)])

sage: Polygon(vertices=[(0, 0), (1, 0), (0, 1)], lengths=[1, 1, 1])
Traceback (most recent call last):
...
ValueError: polygon does not have the prescribed lengths

Currently, we cannot create a polygon from just lengths:

sage: Polygon(lengths=[1, 1, 1])
Traceback (most recent call last):
...
NotImplementedError: one of vertices, edges, or angles must be set

Polygons do not have to be convex:

sage: p = Polygon(vertices=[(0, 0), (1, 1), (2, 0), (2, 4), (0, 4)])
sage: p.describe_polygon()
('a', 'non-convex pentagon', 'non-convex pentagons')

Polygons must be positively oriented:

sage: Polygon(vertices=[(0, 0), (0, 1), (1, 0)])
Traceback (most recent call last):
...
ValueError: polygon has negative area; probably the vertices are not in counter-clockwise order

Polygons must have at least three sides:

sage: Polygon(vertices=[(0, 0), (1, 0)])
Traceback (most recent call last):
...
ValueError: polygon must have at least three sides

sage: Polygon(vertices=[(0, 0), (1, 0), (2, 0)])
Traceback (most recent call last):
...
ValueError: polygon has zero area

Currently, polygons must not self-intersect:

sage: p = Polygon(vertices=[(0, 0), (2, 0), (0, 1), (1, -1), (2, 1)])
Traceback (most recent call last):
...
NotImplementedError: polygon self-intersects

Currently, all angles must be less than 2π:

sage: p = Polygon(angles=[14, 1, 1, 1, 1])
Traceback (most recent call last):
...
NotImplementedError: each angle must be in (0, 2π)
class flatsurf.geometry.polygon.PolygonPosition(position_type, edge=None, vertex=None)[source]

Describes the position of a point within or outside of a polygon.

EDGE_INTERIOR = 2
INTERIOR = 1
OUTSIDE = 0
VERTEX = 3
get_edge()[source]
get_position_type()[source]
get_vertex()[source]
is_in_boundary()[source]

Return true if the position is in the boundary of the polygon (either the interior of an edge or a vertex).

is_in_edge_interior()[source]
is_in_interior()[source]
is_inside()[source]

Return true if the position is not outside the closure of the polygon

is_outside()[source]
is_vertex()[source]
class flatsurf.geometry.polygon.PolygonsConstructor[source]
rectangle(width, height, **kwds)[source]

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons

sage: polygons.rectangle(1,2)
Polygon(vertices=[(0, 0), (1, 0), (1, 2), (0, 2)])

sage: K.<sqrt2> = QuadraticField(2)
sage: polygons.rectangle(1,sqrt2)
Polygon(vertices=[(0, 0), (1, 0), (1, sqrt2), (0, sqrt2)])
sage: _.category()
Category of convex simple euclidean rectangles over Number Field in sqrt2 with defining polynomial x^2 - 2 with sqrt2 = 1.414213562373095?
static regular_ngon(n, field=None)[source]

Return a regular n-gon with unit length edges, first edge horizontal, and other vertices lying above this edge.

Assuming field is None (by default) the polygon is defined over a NumberField (the minimal number field determined by n). Otherwise you can set field equal to AA to define the polygon over the Algebraic Reals. Other values for the field parameter will result in a ValueError.

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons

sage: p = polygons.regular_ngon(17)
sage: p
Polygon(vertices=[(0, 0), (1, 0), ..., (-1/2*a^14 + 15/2*a^12 - 45*a^10 + 275/2*a^8 - 225*a^6 + 189*a^4 - 70*a^2 + 15/2, 1/2*a)])

sage: polygons.regular_ngon(3,field=AA)
Polygon(vertices=[(0, 0), (1, 0), (1/2, 0.866025403784439?)])
static right_triangle(angle, leg0=None, leg1=None, hypotenuse=None)[source]

Return a right triangle in a number field with an angle of pi*angle.

You can specify the length of the first leg (leg0), the second leg (leg1), or the hypotenuse.

EXAMPLES:

sage: from flatsurf import polygons

sage: P = polygons.right_triangle(1/3, 1)
sage: P
Polygon(vertices=[(0, 0), (1, 0), (1, a)])
sage: P.base_ring()
Number Field in a with defining polynomial y^2 - 3 with a = 1.732050807568878?

sage: polygons.right_triangle(1/4,1)
Polygon(vertices=[(0, 0), (1, 0), (1, 1)])
sage: polygons.right_triangle(1/4,1).base_ring()
Rational Field
square(side=1, **kwds)[source]

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons

sage: polygons.square()
Polygon(vertices=[(0, 0), (1, 0), (1, 1), (0, 1)])
sage: polygons.square(base_ring=QQbar).category()
Category of convex simple euclidean rectangles over Algebraic Field
triangle(a, b, c)[source]

Return the triangle with angles a*pi/N,b*pi/N,c*pi/N where N=a+b+c.

INPUT:

  • a, b, c – integers

EXAMPLES:

sage: from flatsurf.geometry.polygon import polygons
sage: T = polygons.triangle(3,4,5)
sage: T
Polygon(vertices=[(0, 0), (1, 0), (-1/2*c0 + 3/2, -1/2*c0 + 3/2)])
sage: T.base_ring()
Number Field in c0 with defining polynomial x^2 - 3 with c0 = 1.732050807568878?

sage: polygons.triangle(1,2,3).angles()
(1/12, 1/6, 1/4)

Some fairly complicated examples:

sage: polygons.triangle(1, 15, 21)  # long time (2s)
Polygon(vertices=[(0, 0),
                  (1, 0),
                  (1/2*c^34 - 17*c^32 + 264*c^30 - 2480*c^28 + 15732*c^26 - 142481/2*c^24 + 237372*c^22 - 1182269/2*c^20 +
                   1106380*c^18 - 1552100*c^16 + 3229985/2*c^14 - 2445665/2*c^12 + 654017*c^10 - 472615/2*c^8 + 107809/2*c^6 - 13923/2*c^4 + 416*c^2 - 6,
                   -1/2*c^27 + 27/2*c^25 - 323/2*c^23 + 1127*c^21 - 10165/2*c^19 + 31009/2*c^17 - 65093/2*c^15 + 46911*c^13 - 91091/2*c^11 + 57355/2*c^9 - 10994*c^7 + 4621/2*c^5 - 439/2*c^3 + 6*c)])

sage: polygons.triangle(2, 13, 26)  # long time (3s)
Polygon(vertices=[(0, 0),
                  (1, 0),
                  (1/2*c^30 - 15*c^28 + 405/2*c^26 - 1625*c^24 + 8625*c^22 - 31878*c^20 + 168245/2*c^18 - 159885*c^16 + 218025*c^14 - 209950*c^12 + 138567*c^10 - 59670*c^8 + 15470*c^6 - 2100*c^4 + 225/2*c^2 - 1/2,
                   -1/2*c^39 + 19*c^37 - 333*c^35 + 3571*c^33 - 26212*c^31 + 139593*c^29 - 557844*c^27 + 1706678*c^25 - 8085237/2*c^23 + 7449332*c^21 -
                   10671265*c^19 + 11812681*c^17 - 9983946*c^15 + 6317339*c^13 - 5805345/2*c^11 + 1848183/2*c^9 - 378929/2*c^7 + 44543/2*c^5 - 2487/2*c^3 + 43/2*c)])