Source code for pyfeyn2.render.ascii

from typing import List

from pyfeyn2.feynmandiagram import Point
from pyfeyn2.render.latex import LatexRender
from pyfeyn2.render.render import Render


[docs]class ASCIILine: def __init__(self, begin=" ", end=" ", vert="|", horz="-"): self.begin = begin self.end = end if isinstance(vert, List): self.vert = vert else: self.vert = [vert] if isinstance(horz, List): self.horz = horz else: self.horz = [horz] self.index = 0
[docs] def draw(self, pane, isrc, itar, scalex=1, scaley=1, kickx=0, kicky=0): width = len(pane[0]) height = len(pane) # TODO normalize to width and height as well srcx = int((isrc.x + kickx) * scalex) srcy = int((isrc.y + kicky) * scaley) tarx = int((itar.x + kickx) * scalex) tary = int((itar.y + kicky) * scaley) if abs(srcx - tarx) > abs(srcy - tary): for i in range(srcx, tarx, 1 if srcx < tarx else -1): pane[round(srcy + (tary - srcy) * (i - srcx) / (-srcx + tarx))][ i ] = self.horz[self.index % len(self.horz)] self.index += 1 else: for i in range(srcy, tary, 1 if srcy < tary else -1): pane[i][ round(srcx + (tarx - srcx) * (i - srcy) / (-srcy + tary)) ] = self.vert[self.index % len(self.vert)] self.index += 1 pane[tary][tarx] = self.vert[self.index % len(self.vert)] self.index += 1 if self.begin is not None and self.begin != "": pane[srcy][srcx] = self.begin if self.end is not None and self.end != "": pane[tary][tarx] = self.end
[docs]class Gluon(ASCIILine): def __init__(self): super().__init__(begin="O", end="O", vert="O", horz="O")
[docs]class Photon(ASCIILine): def __init__(self): super().__init__(begin="*", end="*", vert=["(", ")"], horz="~")
[docs]namedlines = {"gluon": Gluon, "photon": Photon}
[docs]class ASCIIRender(Render): """Renders Feynman diagrams to ASCII art.""" def __init__(self, fd, *args, **kwargs): super().__init__(fd, *args, **kwargs)
[docs] def render(self, file=None, show=True, resolution=100, width=100, height=20): pane = [] for i in range(height): pane.append([" "] * width) maxx = minx = maxy = miny = 0 for l in self.fd.legs: if l.x < minx: minx = l.x if l.x > maxx: maxx = l.x if l.y < miny: miny = l.y if l.y > maxy: maxy = l.y for l in self.fd.vertices: if l.x < minx: minx = l.x if l.x > maxx: maxx = l.x if l.y < miny: miny = l.y if l.y > maxy: maxy = l.y scalex = (width - 1) / (maxx - minx) scaley = (height - 1) / (maxy - miny) kickx = -minx kicky = -miny fmt = {"scalex": scalex, "kickx": kickx, "scaley": scaley, "kicky": kicky} for p in self.fd.propagators: src = self.fd.get_point(p.source) tar = self.fd.get_point(p.target) namedlines[p.type]().draw(pane, src, tar, **fmt) for l in self.fd.legs: tar = self.fd.get_point(l.target) if l.sense[:2] == "in" or l.sense[:8] == "anti-out": namedlines[l.type]().draw(pane, Point(l.x, l.y), tar, **fmt) elif l.sense[:3] == "out" or l.sense[:9] == "anti-in": namedlines[l.type]().draw(pane, tar, Point(l.x, l.y), **fmt) joined = "\n".join(["".join(row) for row in pane]) if show: print(joined) return joined
[docs] def valid_type(typ: str) -> bool: if typ.lower() in namedlines: return True return False