def ward(n): r""" Return the surface formed by gluing a regular 2n-gon to two regular n-gons. These surfaces have Veech's lattice property due to work of Ward. EXAMPLES:: sage: from flatsurf import * sage: s=translation_surfaces.ward(3) sage: TestSuite(s).run() sage: s=translation_surfaces.ward(7) sage: TestSuite(s).run() """ assert n>=3 from .polygon import polygons from .surface import Surface_list from .translation_surface import TranslationSurface o = ZZ_2*polygons.regular_ngon(2*n) p1 = polygons(*[o.edge((2*i+n)%(2*n)) for i in xrange(n)]) p2 = polygons(*[o.edge((2*i+n+1)%(2*n)) for i in xrange(n)]) s = Surface_list(base_ring=o.parent().field()) s.add_polygon(o) s.add_polygon(p1) s.add_polygon(p2) s.change_polygon_gluings(1, [(0,2*i) for i in xrange(n)]) s.change_polygon_gluings(2, [(0,2*i+1) for i in xrange(n)]) s.make_immutable() return TranslationSurface(s)
def mcmullen_L(l1,l2,l3,l4): r""" Return McMullen's L shaped surface with parameters l1, l2, l3, l4. Polygon labels and lengths are marked below. +-----+ | | | 1 |l1 | | | | l4 +-----+---------+ | | | 0 |l2 | | +-----+---------+ l3 Note that this surface may not work correctly yet due to a non-strictly convex polygon in the representation. EXAMPLES:: sage: from flatsurf import * sage: s = translation_surfaces.mcmullen_L(1,1,1,1) sage: TestSuite(s).run() """ from .polygon import polygons from .surface import Surface_list from .translation_surface import TranslationSurface from sage.structure.sequence import Sequence field = Sequence([l1,l2,l3,l4]).universe() if not field.is_field(): field = field.fraction_field() s=Surface_list(base_ring=field) s.add_polygon(polygons((l3,0),(l4,0),(0,l2),(-l4,0),(-l3,0),(0,-l2), ring=field)) s.add_polygon(polygons((l3,0),(0,l1),(-l3,0),(0,-l1), ring=field)) s.change_edge_gluing(0,0,1,2) s.change_edge_gluing(0,1,0,3) s.change_edge_gluing(0,2,0,5) s.change_edge_gluing(0,4,1,0) s.change_edge_gluing(1,1,1,3) s.make_immutable() return TranslationSurface(s)
def example(): r""" Construct a SimilaritySurface from a pair of triangles. TESTS:: sage: from flatsurf import * sage: ex = similarity_surfaces.example() sage: ex SimilaritySurface built from 2 polygons sage: TestSuite(ex).run() """ from .similarity_surface import SimilaritySurface from .surface import Surface_list from .polygon import polygons from sage.rings.rational_field import QQ s=Surface_list(base_ring=QQ) s.add_polygon(polygons(vertices=[(0,0), (2,-2), (2,0)],ring=QQ)) # gets label 0 s.add_polygon(polygons(vertices=[(0,0), (2,0), (1,3)],ring=QQ)) # gets label 1 s.change_polygon_gluings(0, [(1,1), (1,2), (1,0)]) s.make_immutable() return SimilaritySurface(s)
def polygon_double(P): r""" Return the ConeSurface associated to the billiard in the polygon ``P``. Differs from billiard(P) only in the graphical display. Here, we display the polygons separately. """ from .polygon import polygons from .cone_surface import ConeSurface from sage.matrix.constructor import matrix n = P.num_edges() r = matrix(2, [-1,0,0,1]) Q = polygons(edges=[r*v for v in reversed(P.edges())]) surface = Surface_list(base_ring = P.base_ring()) surface.add_polygon(P) # gets label 0) surface.add_polygon(Q) # gets label 1 surface.change_polygon_gluings(0,[(1,n-i-1) for i in xrange(n)]) surface.make_immutable() return ConeSurface(surface)
def billiard(P): r""" Return the ConeSurface associated to the billiard in the polygon ``P``. EXAMPLES:: sage: from flatsurf import * sage: P = polygons(vertices=[(0,0), (1,0), (0,1)]) sage: from flatsurf.geometry.rational_cone_surface import RationalConeSurface sage: Q = RationalConeSurface(similarity_surfaces.billiard(P)) sage: Q RationalConeSurface built from 2 polygons sage: Q.underlying_surface() <class 'flatsurf.geometry.surface.Surface_list'> sage: M = Q.minimal_translation_cover() sage: M TranslationSurface built from 8 polygons sage: TestSuite(M).run() """ from .polygon import polygons from .surface import Surface_list from .cone_surface import ConeSurface from sage.matrix.constructor import matrix n = P.num_edges() r = matrix(2, [-1,0,0,1]) Q = polygons(edges=[r*v for v in reversed(P.edges())]) surface = Surface_list(base_ring = P.base_ring()) surface.add_polygon(P) # gets label 0) surface.add_polygon(Q) # gets label 1 surface.change_polygon_gluings(0,[(1,n-i-1) for i in xrange(n)]) surface.make_immutable() s=ConeSurface(surface) gs = s.graphical_surface(edge_labels=False, polygon_labels=False) gs.make_adjacent(0,0,reverse=True) return s
def triangle_flip(self, l1, e1, in_place=False, test=False): r""" Flips the diagonal of the quadrilateral formed by two triangles glued together along the provided edge (l1,e1). This can be broken into two steps: join along the edge to form a convex quadilateral, then cut along the other diagonal. Raises a ValueError if this quadrilateral would be non-convex. Parameters ---------- l1 label of polygon e1 : integer edge of the polygon in_place : boolean if True do the flip to the current surface which must be mutable. In this case the updated surface will be returned. Otherwise a mutable copy is made and then an edge is flipped, which is then returned. test : boolean if True we don't actually flip, and we return True or False depending on whether or not the flip would be successful. EXAMPLES:: sage: from flatsurf import * sage: s=similarity_surfaces.right_angle_triangle(ZZ(1),ZZ(1)) sage: print(s.polygon(0)) Polygon: (0, 0), (1, 0), (0, 1) sage: print s.triangle_flip(0, 0, test=True) False sage: print s.triangle_flip(0, 1, test=True) True sage: print s.triangle_flip(0, 2, test=True) False sage: from flatsurf import * sage: s=similarity_surfaces.right_angle_triangle(ZZ(1),ZZ(1)) sage: from flatsurf.geometry.surface import Surface_fast sage: s=s.__class__(Surface_fast(s, mutable=True)) sage: try: ....: s.triangle_flip(0,0,in_place=True) ....: except ValueError as e: ....: print e Gluing triangles along this edge yields a non-convex quadrilateral. sage: print s.triangle_flip(0,1,in_place=True) ConeSurface built from 2 polygons sage: print s.polygon(0) Polygon: (0, 0), (1, 1), (0, 1) sage: print s.polygon(1) Polygon: (0, 0), (-1, -1), (0, -1) sage: for p in s.edge_iterator(gluings=True): ....: print p ((0, 0), (1, 0)) ((0, 1), (0, 2)) ((0, 2), (0, 1)) ((1, 0), (0, 0)) ((1, 1), (1, 2)) ((1, 2), (1, 1)) sage: try: ....: s.triangle_flip(0,2,in_place=True) ....: except ValueError as e: ....: print e ....: Gluing triangles along this edge yields a non-convex quadrilateral. sage: from flatsurf import * sage: p=polygons((2,0),(-1,3),(-1,-3)) sage: s=similarity_surfaces.self_glued_polygon(p) sage: from flatsurf.geometry.surface import Surface_fast sage: s=s.__class__(Surface_fast(s,mutable=True)) sage: s.triangle_flip(0,1,in_place=True) HalfTranslationSurface built from 1 polygon sage: for x in s.label_iterator(polygons=True): ....: print x (0, Polygon: (0, 0), (3, 3), (1, 3)) sage: for x in s.edge_iterator(gluings=True): ....: print x ((0, 0), (0, 0)) ((0, 1), (0, 1)) ((0, 2), (0, 2)) sage: TestSuite(s).run() """ if test: # Just test if the flip would be successful p1=self.polygon(l1) if not p1.num_edges()==3: return false l2,e2 = self.opposite_edge(l1,e1) p2 = self.polygon(l2) if not p2.num_edges()==3: return false sim = self.edge_transformation(l2,e2) hol = sim( p2.vertex( (e2+2)%3 ) - p1.vertex((e1+2)%3) ) from flatsurf.geometry.polygon import wedge_product return wedge_product(p1.edge((e1+2)%3), hol) > 0 and \ wedge_product(p1.edge((e1+1)%3), hol) > 0 if in_place: s=self.underlying_surface() else: from flatsurf.geometry.surface import Surface_fast s=Surface_fast(surface=self.underlying_surface(), \ mutable=True, dictionary=True) p1=self.polygon(l1) if not p1.num_edges()==3: raise ValueError("The polygon with the provided label is not a triangle.") l2,e2 = self.opposite_edge(l1,e1) p2 = self.polygon(l2) if not p2.num_edges()==3: raise ValueError("The polygon opposite the provided edge is not a triangle.") sim = self.edge_transformation(l2,e2) m = sim.derivative() hol = sim( p2.vertex( (e2+2)%3 ) ) - p1.vertex((e1+2)%3) from flatsurf import polygons try: np1 = polygons(edges=[hol, m * p2.edge((e2+2)%3), p1.edge((e1+1)%3)]) np2 = polygons(edges=[-hol, p1.edge((e1+2)%3), m * p2.edge((e2+1)%3)]) except (ValueError, TypeError): raise ValueError("Gluing triangles along this edge yields a non-convex quadrilateral.") # Old gluings: pairs = [self.opposite_edge(l2,(e2+2)%3), \ self.opposite_edge(l1,(e1+1)%3), \ self.opposite_edge(l1,(e1+2)%3), \ self.opposite_edge(l2,(e2+1)%3)] for i, (l,e) in enumerate(pairs): if l==l1: if e==(e1+1)%3: pairs[i]=(l1,2) elif e==(e1+2)%3: pairs[i]=(l2,1) else: raise ValueError("Surfaced passed has errors in polygon gluings.") elif l==l2: if e==(e2+1)%3: pairs[i]=(l2,2) elif e==(e2+2)%3: pairs[i]=(l1,1) else: raise ValueError("Surfaced passed has errors in polygon gluings.") if l1==l2: s.change_polygon(l1,np1) s.change_edge_gluing(l1,0,l1,0) s.change_edge_gluing(l1,1,pairs[0][0],pairs[0][1]) s.change_edge_gluing(l1,2,pairs[1][0],pairs[1][1]) else: s.change_polygon(l1,np1) s.change_polygon(l2,np2) s.change_edge_gluing(l1,0,l2,0) s.change_edge_gluing(l1,1,pairs[0][0],pairs[0][1]) s.change_edge_gluing(l1,2,pairs[1][0],pairs[1][1]) s.change_edge_gluing(l2,1,pairs[2][0],pairs[2][1]) s.change_edge_gluing(l2,2,pairs[3][0],pairs[3][1]) if in_place: return self else: return self.__class__(s)