Beispiel #1
0
    def l_infinity_delaunay_triangulation(self,
                                          triangulated=False,
                                          in_place=False,
                                          limit=None,
                                          direction=None):
        r"""
        Returns a L-infinity Delaunay triangulation of a surface, or make some
        triangle flips to get closer to the Delaunay decomposition.

        INPUT:

        - ``triangulated`` -- optional (boolean, default ``False``) If true, the
          algorithm assumes the surface is already triangulated. It does this
          without verification.

        - ``in_place`` -- optional (boolean, default ``False``) If true, the
          triangulating and the triangle flips are done in place. Otherwise, a
          mutable copy of the surface is made.

        - ``limit`` -- optional (positive integer) If provided, then at most ``limit``
            many diagonal flips will be done.

        - ``direction`` -- optional (vector). Used to determine labels when a
          pair of triangles is flipped. Each triangle has a unique separatrix
          which points in the provided direction or its negation. As such a
          vector determines a sign for each triangle.  A pair of adjacent
          triangles have opposite signs. Labels are chosen so that this sign is
          preserved (as a function of labels).

        EXAMPLES::

            sage: from flatsurf import *
            sage: s0 = translation_surfaces.veech_double_n_gon(5)
            sage: field = s0.base_ring()
            sage: a = field.gen()
            sage: m = matrix(field, 2, [2,a,1,1])

            sage: s = m*s0
            sage: s = s.l_infinity_delaunay_triangulation()
            sage: TestSuite(s).run()

            sage: s = (m**2)*s0
            sage: s = s.l_infinity_delaunay_triangulation()
            sage: TestSuite(s).run()

            sage: s = (m**3)*s0
            sage: s = s.l_infinity_delaunay_triangulation()
            sage: TestSuite(s).run()
        """
        if not self.is_finite():
            raise NotImplementedError(
                "no L-infinity Delaunay implemented for infinite surfaces")
        if triangulated:
            if in_place:
                s = self
            else:
                from flatsurf.geometry.surface import Surface_dict
                s = self.__class__(Surface_dict(surface=self, mutable=True))
        else:
            from flatsurf.geometry.surface import Surface_list
            s = self.__class__(
                Surface_list(surface=self.triangulate(in_place=in_place),
                             mutable=True))

        if direction is None:
            base_ring = self.base_ring()
            direction = self.vector_space()(
                (base_ring.zero(), base_ring.one()))
        else:
            assert not direction.is_zero()

        triangles = set(s.label_iterator())
        if limit is None:
            limit = -1
        else:
            limit = int(limit)
        while triangles and limit:
            p1 = triangles.pop()
            for e1 in range(3):
                p2, e2 = s.opposite_edge(p1, e1)
                if s._edge_needs_flip_Linfinity(p1, e1, p2, e2):
                    s.triangle_flip(p1, e1, in_place=True, direction=direction)
                    triangles.add(p1)
                    triangles.add(p2)
                    limit -= 1
        return s
Beispiel #2
0
def surface_to_xml_string(s, complain=True):
    r""" 
    Convert the surface s into a XML string.
    
    Note that this only encodes the Surface part of the object and not the SimilaritySurface 
    wrapper.
    
    By default complain=True, and it will print warning messages and raise errors if it doesn't 
    think you will be able to reconstruct the surface using surface_from_xml_string.

    Currently s should be Surface_list (or a wrapped Surface_list). If not and complain=True,
    an error message will be printed and the surface will be converted to Surface_list. If 
    complain=False, the surface will be encoded but you may not be able to recover it.
    
    Also the surface should be defined over the rationals. Otherwise a ValueError is raised, which
    can be disabled by setting complain=False.
    """
    if not s.is_finite():
        raise ValueError("Can only xml encode a finite surface.")
    from flatsurf.geometry.similarity_surface import SimilaritySurface
    if isinstance(s, SimilaritySurface):
        s = s.underlying_surface()
    from flatsurf.geometry.surface import Surface_list
    if complain:
        if not isinstance(s, Surface_list):
            # Convert to surface list
            print("Warning:surface_to_xml_string is converting to Surface_list before encoding, "+\
                  " labels will likely be changed. "+\
                  "If this is not desired, "+
                  "call surface_to_xml_string with complain=False.")
            s = Surface_list(surface=s)

    from xml.sax.saxutils import escape
    output = []
    output.append('<surface>')

    # Include the type of surface (in case we care about it in the future)
    output.append('<type>')
    output.append(escape(repr(type(s))))
    output.append('</type>')

    from sage.rings.rational_field import QQ
    if complain and s.base_ring() != QQ:
        raise ValueError("Refusing to encode surface with base_ring!=QQ, "+\
                         "because we can not guarantee we bring the surface back. "+
                         "If you would like to encode it anyway, "+
                         "call surface_to_xml_string with complain=False.")

    output.append('<base_ring>')
    output.append(escape(repr(s.base_ring())))
    output.append('</base_ring>')

    output.append('<base_label>')
    output.append(escape(repr(s.base_label())))
    output.append('</base_label>')

    output.append('<polygons>')
    for label in s.label_iterator():
        output.append('<polygon>')
        output.append('<label>')
        output.append(escape(repr(label)))
        output.append('</label>')
        p = s.polygon(label)
        for e in range(p.num_edges()):
            output.append('<edge>')
            v = p.edge(e)
            output.append('<x>')
            output.append(escape(repr(v[0])))
            output.append('</x>')
            output.append('<y>')
            output.append(escape(repr(v[1])))
            output.append('</y>')
            output.append('</edge>')
        output.append('</polygon>')
    output.append('</polygons>')

    output.append('<gluings>')
    for l, e in s.edge_iterator():
        ll, ee = s.opposite_edge(l, e)
        if ll < l or (ll == l and ee < e):
            continue
        output.append('<glue>')
        output.append('<l>')
        output.append(escape(repr(l)))
        output.append('</l>')
        output.append('<e>')
        output.append(escape(repr(e)))
        output.append('</e>')
        output.append('<ll>')
        output.append(escape(repr(ll)))
        output.append('</ll>')
        output.append('<ee>')
        output.append(escape(repr(ee)))
        output.append('</ee>')
        output.append('</glue>')
    output.append('</gluings>')

    output.append('</surface>')
    return ''.join(output)
Beispiel #3
0
def surface_to_xml_string(s, complain=True):
    r""" 
    Convert the surface s into a XML string.
    
    Note that this only encodes the Surface part of the object and not the SimilaritySurface 
    wrapper.
    
    By default complain=True, and it will print warning messages and raise errors if it doesn't 
    think you will be able to reconstruct the surface using surface_from_xml_string.

    Currently s should be Surface_list (or a wrapped Surface_list). If not and complain=True,
    an error message will be printed and the surface will be converted to Surface_list. If 
    complain=False, the surface will be encoded but you may not be able to recover it.
    
    Also the surface should be defined over the rationals. Otherwise a ValueError is raised, which
    can be disabled by setting complain=False.
    """
    if not s.is_finite():
        raise ValueError("Can only xml encode a finite surface.")
    from flatsurf.geometry.similarity_surface import SimilaritySurface
    if isinstance(s,SimilaritySurface):
        s=s.underlying_surface()
    from flatsurf.geometry.surface import Surface_list
    if complain:
        if not isinstance(s,Surface_list):
            # Convert to surface list
            print("Warning:surface_to_xml_string is converting to Surface_list before encoding, "+\
                  " labels will likely be changed. "+\
                  "If this is not desired, "+
                  "call surface_to_xml_string with complain=False.")
            s=Surface_list(surface=s)
    
    from xml.sax.saxutils import escape
    output=[]
    output.append('<surface>')
    
    # Include the type of surface (in case we care about it in the future)
    output.append('<type>')
    output.append(escape(repr(type(s))))
    output.append('</type>')

    from sage.rings.rational_field import QQ
    if complain and s.base_ring()!=QQ:
        raise ValueError("Refusing to encode surface with base_ring!=QQ, "+\
                         "because we can not guarantee we bring the surface back. "+
                         "If you would like to encode it anyway, "+
                         "call surface_to_xml_string with complain=False.")

    output.append('<base_ring>')
    output.append(escape(repr(s.base_ring())))
    output.append('</base_ring>')
    
    output.append('<base_label>')
    output.append(escape(repr(s.base_label())))
    output.append('</base_label>')
    
    output.append('<polygons>')
    for label in s.label_iterator():
        output.append('<polygon>')
        output.append('<label>')
        output.append(escape(repr(label)))
        output.append('</label>')
        p=s.polygon(label)
        for e in xrange(p.num_edges()):
            output.append('<edge>')
            v=p.edge(e)
            output.append('<x>')
            output.append(escape(repr(v[0])))
            output.append('</x>')
            output.append('<y>')
            output.append(escape(repr(v[1])))
            output.append('</y>')
            output.append('</edge>')
        output.append('</polygon>')
    output.append('</polygons>')

    output.append('<gluings>')
    for l,e in s.edge_iterator():
        ll,ee=s.opposite_edge(l,e)
        if ll<l or (ll==l and ee<e):
            continue
        output.append('<glue>')
        output.append('<l>')
        output.append(escape(repr(l)))
        output.append('</l>')
        output.append('<e>')
        output.append(escape(repr(e)))
        output.append('</e>')
        output.append('<ll>')
        output.append(escape(repr(ll)))
        output.append('</ll>')
        output.append('<ee>')
        output.append(escape(repr(ee)))
        output.append('</ee>')
        output.append('</glue>')
    output.append('</gluings>')
    
    output.append('</surface>')
    return ''.join(output)
Beispiel #4
0
def _surface_from_ElementTree(tree):
    from flatsurf.geometry.surface import Surface_list
    node = tree.find("type")
    if node is None:
        raise ValueError('Failed to find tag named "node"')
    if node.text != repr(Surface_list):
        raise NotImplementedError("Currently can only reconstruct from Surface_list. "+\
                        "Found type "+node.text)

    node = tree.find("base_ring")
    if node is None:
        raise ValueError('Failed to find tag named "base_ring"')
    from sage.rings.rational_field import QQ
    if node.text == repr(QQ):
        base_ring = QQ
    else:
        raise NotImplementedError("Can only reconstruct when base_ring=QQ. "+\
                                  "Found "+tree.find("base_ring").text)

    s = Surface_list(QQ)

    # Import the polygons
    polygons = tree.find("polygons")
    if polygons is None:
        raise ValueError('Failed to find tag named "polygons"')
    from flatsurf.geometry.polygon import ConvexPolygons
    P = ConvexPolygons(base_ring)
    for polygon in polygons.findall("polygon"):
        node = polygon.find("label")
        if node is None:
            raise ValueError('Failed to find tag <label> in <polygon>')
        label = int(node.text)
        edges = []
        for edge in polygon.findall("edge"):
            node = edge.find("x")
            if node is None:
                raise ValueError(
                    'Failed to find tag <x> in <edge> in <polygon> with label='
                    + str(label))
            x = base_ring(node.text)
            node = edge.find("y")
            if node is None:
                raise ValueError(
                    'Failed to find tag <y> in <edge> in <polygon> with label='
                    + str(label))
            y = base_ring(node.text)
            edges.append((x, y))
        p = P(edges=edges)
        s.add_polygon(p, label=label)
    if s.num_polygons() == 0:
        raise ValueError("Failed to add any polygons.")

    # Glue the edges
    gluings = tree.find("gluings")
    if gluings is None:
        raise ValueError('Failed to find tag named "gluings"')
    for glue in gluings.findall("glue"):
        node = glue.find("l")
        if node is None:
            raise ValueError('Failed to find tag <l> in <glue>.')
        l = int(node.text)
        node = glue.find("e")
        if node is None:
            raise ValueError('Failed to find tag <e> in <glue>.')
        e = int(node.text)
        node = glue.find("ll")
        if node is None:
            raise ValueError('Failed to find tag <ll> in <glue>.')
        ll = int(node.text)
        node = glue.find("ee")
        if node is None:
            raise ValueError('Failed to find tag <ee> in <glue>.')
        ee = int(node.text)
        s.change_edge_gluing(l, e, ll, ee)

    node = tree.find("base_label")
    if node is None:
        raise ValueError('Failed to find tag named "base_label"')
    base_label = int(node.text)
    s.change_base_label(base_label)

    # Return the surface:
    return s
Beispiel #5
0
def _surface_from_ElementTree(tree):
    from flatsurf.geometry.surface import Surface_list
    node=tree.find("type")
    if node is None:
        raise ValueError('Failed to find tag named "node"')
    if node.text != repr(Surface_list):
        raise NotImplementedError("Currently can only reconstruct from Surface_list. "+\
                        "Found type "+node.text)

    node=tree.find("base_ring")
    if node is None:
        raise ValueError('Failed to find tag named "base_ring"')
    from sage.rings.rational_field import QQ
    if node.text == repr(QQ):
        base_ring=QQ
    else:
        raise NotImplementedError("Can only reconstruct when base_ring=QQ. "+\
                                  "Found "+tree.find("base_ring").text)

    s=Surface_list(QQ)
    
    # Import the polygons
    polygons=tree.find("polygons")
    if polygons is None:
        raise ValueError('Failed to find tag named "polygons"')
    from flatsurf.geometry.polygon import Polygons
    P=Polygons(base_ring)
    for polygon in polygons.findall("polygon"):
        node=polygon.find("label")
        if node is None:
            raise ValueError('Failed to find tag <label> in <polygon>')
        label=int(node.text)
        edges=[]
        for edge in polygon.findall("edge"):
            node=edge.find("x")
            if node is None:
                raise ValueError('Failed to find tag <x> in <edge> in <polygon> with label='+str(label))
            x=base_ring(node.text)
            node=edge.find("y")
            if node is None:
                raise ValueError('Failed to find tag <y> in <edge> in <polygon> with label='+str(label))
            y=base_ring(node.text)
            edges.append((x,y))
        p=P(edges=edges)
        s.add_polygon(p,label=label)
    if s.num_polygons()==0:
        raise ValueError("Failed to add any polygons.")
    
    # Glue the edges
    gluings=tree.find("gluings")
    if gluings is None:
        raise ValueError('Failed to find tag named "gluings"')
    for glue in gluings.findall("glue"):
        node=glue.find("l")
        if node is None:
            raise ValueError('Failed to find tag <l> in <glue>.')
        l=int(node.text)
        node=glue.find("e")
        if node is None:
            raise ValueError('Failed to find tag <e> in <glue>.')
        e=int(node.text)
        node=glue.find("ll")
        if node is None:
            raise ValueError('Failed to find tag <ll> in <glue>.')
        ll=int(node.text)
        node=glue.find("ee")
        if node is None:
            raise ValueError('Failed to find tag <ee> in <glue>.')
        ee=int(node.text)
        s.change_edge_gluing(l,e,ll,ee)

    node=tree.find("base_label")
    if node is None:
        raise ValueError('Failed to find tag named "base_label"')
    base_label = int(node.text)
    s.change_base_label(base_label)
        
    # Return the surface:
    return s