Source code for pyfeyn2.render.pyx.lines

"""Various particle line types."""


import pyx
from pyx import color

from pyfeyn2.render.pyx import config
from pyfeyn2.render.pyx.deco import Arrow, LineLabel, ParallelArrow
from pyfeyn2.render.pyx.diagrams import FeynDiagram
from pyfeyn2.render.pyx.paint import CENTER
from pyfeyn2.render.pyx.points import Point
from pyfeyn2.render.pyx.utils import Visible, defunit


## Line base class
[docs]class Line(Visible): "Base class for all objects which connect points in Feynman diagrams"
[docs] def __init__( self, point1, point2, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): """Constructor.""" self.p1 = point1 self.p2 = point2 self.styles = styles if styles is not None else [] self.arcthrupoint = arcthrupoint self.is3D = is3D self.arrows = arrows if arrows is not None else [] self.labels = labels if labels is not None else [] ## Add this to the current diagram automatically FeynDiagram.currentDiagram.add(self)
[docs] def addLabel( self, text, pos=0.5, displace=-0.25, angle=0, size=pyx.text.size.normalsize, halign=CENTER, valign=None, **kwargs ): """Add a LaTeX label to this line, either via parameters or actually as a TeXLabel object.""" if text is None: return self if config.getOptions().DEBUG: print("Adding label: " + text) # if text.__class__ == "Label": # self.labels.append(label) # else: self.labels.append( LineLabel( text=text, line=self, pos=pos, displace=displace, angle=angle, size=size, halign=halign, valign=valign, ) ) if config.getOptions().DEBUG: print("Labels = " + str(self.labels)) return self
[docs] def addParallelArrow( self, pos=0.5, displace=0.3, length=0.5 * pyx.unit.v_cm, size=6 * pyx.unit.v_pt, angle=45, constriction=0.8, sense=+1, curved=False, stems=1, stemsep=0.03, ): """Add an arrow pointing along the line.""" self.labels.append( ParallelArrow( self, pos=pos, displace=displace, length=length, size=size, angle=angle, constriction=constriction, sense=sense, curved=curved, stems=stems, stemsep=stemsep, ) ) return self
[docs] def removeLabels(self): """Remove the labels from this line.""" self.labels = [] return self
[docs] def fracpoint(self, frac): """ Get a new Point representing the point at the given fraction along the fundamental line (i.e. no truncation or deformation). TODO: Handle units properly. """ p = self.getPath() ## no truncation or deformation x, y = p.at(p.begin() + frac * p.arclen()) return Point(x / defunit, y / defunit)
[docs] def setArrows(self, arrows): """Define the arrows on this line.""" ## TODO: Check that the arg is a list self.arrows = [] for i in arrows: if i.__class__ == "deco.Arrow": self.arrows.append(i) else: self.arrows.append(Arrow(pos=i)) return self
[docs] def addArrow(self, position=0.53, arrow=None): """Add an arrow to the line at the specified position, which is a number between 0 and 1, representing the fraction along the line at which the arrow should be placed. The default arrow style can be overridden by explicitly supplying an arrow object as the 'arrow' argument, in which case the position argument will be ignored.""" if arrow: self.arrows.append(arrow) else: self.arrows.append(Arrow(pos=position)) return self
[docs] def removeArrows(self): """Remove all arrows from this line.""" self.arrows = [] return self
[docs] def arcThru(self, arcpoint=None, x=None, y=None): """Set the point through which this line will arc. Either pass a Point or set x, y as floats.""" if arcpoint is not None: self.arcthrupoint = arcpoint elif x is not None and y is not None: self.arcthrupoint = Point(x, y) else: raise Exception("Tried to set an arcpoint with invalid arguments") return self
[docs] def straighten(self): """Make this line a straight line between start and end.""" self.arcthrupoint = None return self
[docs] def bend(self, amount): """Bend the line to the right by a given distance.""" if amount is None: return self if amount == 0: self.arcthrupoint = None return self middle = self.p1.midpoint(self.p2) nx = (middle.y() - self.p1.y()) / abs(self.p1.distance(middle)) ny = (self.p1.x() - middle.x()) / abs(self.p1.distance(middle)) vx = middle.x() - self.p1.x() vy = middle.y() - self.p1.y() if (vx * ny - vy * nx) > 0: nx *= -1 ny *= -1 arcpoint = Point(middle.x() + amount * nx, middle.y() + amount * ny) if config.getOptions().VDEBUG: FeynDiagram.currentDiagram.currentCanvas.stroke( pyx.path.line(middle.x(), middle.y(), arcpoint.x(), arcpoint.y()), [color.rgb.blue], ) self.arcThru(arcpoint) if config.getOptions().DEBUG: print(self.getVisiblePath()) if config.getOptions().VDEBUG: FeynDiagram.currentDiagram.currentCanvas.stroke( self.getVisiblePath(), [color.rgb.blue] ) return self
[docs] def set3D(self, is3d): """Make this line display in '3D'.""" self.is3D = is3d return self
[docs] def getStyles(self, stylelist): """Get the styles associated with this line.""" return self.styles
[docs] def setStyles(self, stylelist): """Set the styles associated with this line.""" self.styles = stylelist return self
[docs] def addStyle(self, style): """Add a style to this line.""" self.styles.append(style) return self
[docs] def addStyles(self, stylelist): """Add some styles to this line.""" self.styles = self.styles + stylelist return self
[docs] def getPath(self): """Get the path taken by this line.""" if self.arcthrupoint is None: ## This is a simple straight line return pyx.path.path( pyx.path.moveto(*(self.p1.getXY())), pyx.path.lineto(*(self.p2.getXY())) ) elif self.p1.x() == self.p2.x() and self.p1.y() == self.p2.y(): ## This is a tadpole-type loop and needs special care; ## We shall assume that the arcthrupoint is meant to be ## the antipode of the basepoint arccenter = self.p1.midpoint(self.arcthrupoint) arcradius = self.p1.distance(self.arcthrupoint) / 2.0 ## TODO Why does a circle work and an arc doesn't? cargs = (arccenter.x(), arccenter.y(), arcradius) circle = pyx.path.circle(*cargs) line = pyx.path.line(self.p1.x(), self.p1.y(), arccenter.x(), arccenter.y()) if config.getOptions().VDEBUG: FeynDiagram.currentDiagram.currentCanvas.stroke(line, [color.rgb.green]) ass, _ = circle.intersect(line) subpaths = circle.split(ass[0]) cpath = subpaths[0] return cpath ## or, with an arc... # arcangle1 = arccenter.arg(self.p1) # arcangle2 = arccenter.arg(self.p1) + 360 # arcargs = (arccenter.x(), arccenter.y(), arcradius, arcangle1, arcangle2) # return pyx.path.path(pyx.path.arc(*arcargs)) else: n13, n23 = None, None ## Work out line gradients try: n13 = (self.p1.y() - self.arcthrupoint.y()) / ( self.p1.x() - self.arcthrupoint.x() ) except ZeroDivisionError: if config.getOptions().DEBUG: print("Grad 1 diverges") n13 = 1e100 try: n23 = (self.p2.y() - self.arcthrupoint.y()) / ( self.p2.x() - self.arcthrupoint.x() ) except ZeroDivisionError: if config.getOptions().DEBUG: print("Grad 2 diverges") n23 = 1e100 ## If gradients match, ## then we have a straight line, so bypass the complexity if n13 == n23: return pyx.path.path( pyx.path.moveto(*(self.p1.getXY())), pyx.path.lineto(*(self.p2.getXY())), ) ## Otherwise work out conjugate gradients and midpoints m13, m23 = None, None try: m13 = -1.0 / n13 except ZeroDivisionError: m13 = 1e100 try: m23 = -1.0 / n23 except ZeroDivisionError: m23 = 1e100 mid13 = self.p1.midpoint(self.arcthrupoint) mid23 = self.p2.midpoint(self.arcthrupoint) ## Line y-intercepts c13 = mid13.y() - m13 * mid13.x() c23 = mid23.y() - m23 * mid23.x() ## Find the centre of the arc xcenter = -(c23 - c13) / (m23 - m13) ycenter = m13 * xcenter + c13 arccenter = Point(xcenter, ycenter) ## Get the angles required for drawing the arc arcradius = arccenter.distance(self.arcthrupoint) arcangle1 = arccenter.arg(self.p1) arcangle2 = arccenter.arg(self.p2) # arcangle3 = arccenter.arg(self.arcthrupoint) arcargs = (arccenter.x(), arccenter.y(), arcradius, arcangle1, arcangle2) if config.getOptions().DEBUG and arcangle1 == arcangle2: print("Arc angles are the same - not drawing anything") ## Calculate cross product to determine direction of arc vec12 = [self.p2.x() - self.p1.x(), self.p2.y() - self.p1.y(), 0.0] vec13 = [ self.arcthrupoint.x() - self.p1.x(), self.arcthrupoint.y() - self.p1.y(), 0.0, ] crossproductZcoord = vec12[0] * vec13[1] - vec12[1] * vec13[0] if crossproductZcoord < 0: return pyx.path.path( pyx.path.moveto(*(self.p1.getXY())), pyx.path.arc(*arcargs) ) else: return pyx.path.path( pyx.path.moveto(*(self.p1.getXY())), pyx.path.arcn(*arcargs) )
[docs] def getVisiblePath(self): """Find the subpath between the endpoints which isn't overshadowed by a blob of some kind""" p1path = self.p1.getPath() p2path = self.p2.getPath() vispath = self.getPath() if config.getOptions().VDEBUG: FeynDiagram.currentDiagram.currentCanvas.stroke(vispath, [color.rgb.green]) if p1path: ass, bs = p1path.intersect(vispath) for b in bs: subpaths = vispath.split(b) if len(subpaths) > 1: if config.getOptions().DEBUG: print("Num subpaths 1 = %d" % len(subpaths)) subpaths.sort(key=lambda x: pyx.unit.tocm(x.arclen())) vispath = subpaths[-1] if config.getOptions().VDEBUG: FeynDiagram.currentDiagram.currentCanvas.stroke( subpaths[0], [color.rgb.blue] ) if config.getOptions().VDEBUG: for a in ass: ix, iy = p1path.at(a) FeynDiagram.currentDiagram.currentCanvas.fill( pyx.path.circle(ix, iy, 0.05), [color.rgb.green] ) if p2path: ass, bs = p2path.intersect(vispath) for b in bs: subpaths = vispath.split(b) if len(subpaths) > 1: if config.getOptions().DEBUG: print("Num subpaths 2 = %d" % len(subpaths)) subpaths.sort(key=lambda x: pyx.unit.tocm(x.arclen())) vispath = subpaths[-1] if config.getOptions().VDEBUG: FeynDiagram.currentDiagram.currentCanvas.stroke( subpaths[0], [color.rgb.red] ) if config.getOptions().VDEBUG: for a in ass: ix, iy = p2path.at(a) FeynDiagram.currentDiagram.currentCanvas.fill( pyx.path.circle(ix, iy, 0.05), [color.rgb.blue] ) if config.getOptions().VDEBUG: FeynDiagram.currentDiagram.currentCanvas.stroke(vispath, [color.rgb.red]) # return pyx.path.circle(-2,-1,0.2) return vispath
[docs] def draw(self, canvas): """Draw this line on the given canvas.""" path = self.getVisiblePath() styles = self.styles + self.arrows if config.getOptions().DEBUG: print("Drawing " + str(self.__class__) + " with styles = " + str(styles)) print(path) canvas.stroke(path, styles) for l in self.labels: l.draw(canvas)
## Fermion is an alias for Line Fermion = Line
[docs]class MultiLine(Line): """A class for drawing multiple parallel straight lines."""
[docs] def __init__( self, point1, point2, n=5, dist=0.2, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): """Constructor.""" Line.__init__(self, point1, point2, styles, arcthrupoint, is3D, arrows, labels) self.n = n self.dist = dist
[docs] def draw(self, canvas): """Draw this multiline on the supplied canvas.""" dist = self.dist n = self.n path = pyx.deformer.parallel(-n / 2.0 * dist).deform(self.getPath()) paths = [path] defo = pyx.deformer.parallel(dist) for _ in range(0, n): path = defo.deform(path) paths.append(path) styles = self.styles + self.arrows for p in paths: canvas.stroke(p, styles) for l in self.labels: l.draw(canvas)
[docs]class Scalar(Line): """A scalar particle line, like a Higgs boson."""
[docs] def __init__( self, point1, point2, linestyle=pyx.style.linestyle.dashed, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): Line.__init__(self, point1, point2, styles, arcthrupoint, is3D, arrows, labels) self.linestyle = linestyle
[docs] def draw(self, canvas): """Draw this scalar line on the given canvas.""" path = self.getVisiblePath() styles = self.styles + [self.linestyle] + self.arrows ## TODO: call base class method? if config.getOptions().DEBUG: print("Drawing " + str(self.__class__) + " with styles = " + str(styles)) print(path) canvas.stroke(path, styles) for l in self.labels: l.draw(canvas)
## Higgs is an alias for Scalar Higgs = Scalar ## Sfermion is also an alias for Scalar Sfermion = Scalar
[docs]class Ghost(Scalar): """A dotted scalar particle line, like a Yang-Mills ghost particle.""" # same as scalar, but default style is dotted
[docs] def __init__( self, point1, point2, linestyle=pyx.style.linestyle.dotted, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): Scalar.__init__( self, point1=point1, point2=point2, styles=styles, arcthrupoint=arcthrupoint, is3D=is3D, arrows=arrows, labels=labels, linestyle=linestyle, )
## DecoratedLine base class
[docs]class DecoratedLine(Line): """Base class for spring and sine-like lines"""
[docs] def __init__( self, point1, point2, amplitude, frequency, extras, invert, linetype, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): """Constructor.""" Line.__init__(self, point1, point2, styles, arcthrupoint, is3D, arrows, labels) self.inverted = invert self.arcradius = amplitude self.frequency = frequency self.extras = extras self.linetype = linetype
[docs] def set3D(self, is3D=True, skipsize=pyx.unit.length(0.04), parity=0): """Make this line display in '3D'.""" self.is3D = is3D self.skipsize3D = skipsize self.parity3D = parity return self
[docs] def invert(self): """Reflect the decoration in the line itself.""" self.inverted = not self.inverted return self
[docs] def getFrequency(self): """Get the rate of occurence of the oscillation.""" return self.frequency
[docs] def setFrequency(self, freq): """Set the rate of occurence of the oscillation.""" self.frequency = freq return self
[docs] def getAmplitude(self): """Get the radius of the oscillation.""" return self.arcradius
[docs] def setAmplitude(self, amplitude): """Set the radius of the oscillation.""" self.arcradius = amplitude return self
[docs] def setExtraCycles(self, extras): """Add some extra (possibly negative) cycles to the oscillation.""" self.extras = extras return self
[docs] def getDeformedPath(self, sign=1): """Get the deformed path.""" return self.getVisiblePath()
[docs]class Gluon(DecoratedLine): """A line with a cycloid deformation"""
[docs] def __init__( self, point1, point2, amplitude=0.15, frequency=1.3, extras=0, invert=False, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): """Constructor.""" DecoratedLine.__init__( self, point1, point2, amplitude, frequency, extras, invert, "gluon", styles, arcthrupoint, is3D, arrows, labels, )
[docs] def getDeformedPath(self, sign=1): """Get the path modified by the coil warping.""" needwindings = ( self.frequency * pyx.unit.tocm(self.getVisiblePath().arclen()) / pyx.unit.tocm(self.arcradius) ) ## Get the whole number of windings and make sure that it's odd so we ## don't get a weird double-back thing intwindings = int(needwindings) intwindings += 2 * self.extras if intwindings % 2 == 0: intwindings -= 1 # deficit = needwindings - intwindings sign = 1 if self.inverted: sign = -1 defo = pyx.deformer.cycloid( self.arcradius, intwindings, curvesperhloop=10, skipfirst=0.0, skiplast=0.0, sign=sign, ) return defo.deform(self.getVisiblePath())
[docs] def draw(self, canvas): """Draw the line on the supplied canvas.""" styles = self.styles + self.arrows if config.getOptions().DEBUG: print("Drawing " + str(self.__class__) + " with styles = " + str(styles)) mypath = self.getDeformedPath() if config.getOptions().DRAFT or not self.is3D: canvas.stroke(mypath, styles) else: para = pyx.deformer.parallel(0.001) _, bs, _ = para.normpath_selfintersections(mypath.normpath(), epsilon=0.01) coil_params = [] for b in bs: coil_params.append(b[self.parity3D] - self.skipsize3D) coil_params.append(b[self.parity3D] + self.skipsize3D) pathbits = mypath.split(coil_params) on = True for pathbit in pathbits: if on: canvas.stroke(pathbit, styles) on = not on ## Labels for l in self.labels: l.draw(canvas)
[docs]class Vector(DecoratedLine): """A line with a sinoid deformation"""
[docs] def __init__( self, point1, point2, amplitude=0.25, frequency=1.0, extras=0, invert=False, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): """Constructor.""" DecoratedLine.__init__( self, point1, point2, amplitude, frequency, extras, invert, "photon", styles, arcthrupoint, is3D, arrows, labels, )
[docs] def getDeformedPath(self, sign=1): """Get the path with the decorative deformation.""" intwindings = int( self.frequency * pyx.unit.tocm(self.getVisiblePath().arclen()) / pyx.unit.tocm(self.arcradius) ) intwindings += self.extras sign = 1 if self.inverted: sign = -1 defo = pyx.deformer.cycloid( self.arcradius, intwindings, curvesperhloop=5, skipfirst=0.0, skiplast=0.0, turnangle=0, sign=sign, ) return defo.deform(self.getVisiblePath())
[docs] def draw(self, canvas): """Draw the line on the supplied canvas.""" styles = self.styles + self.arrows if config.getOptions().DEBUG: print("Drawing " + str(self.__class__) + " with styles = " + str(styles)) canvas.stroke(self.getDeformedPath(), styles) for l in self.labels: l.draw(canvas)
## Photon is an alias for Vector Photon = Vector
[docs]class Graviton(DecoratedLine): """A line with a double sinoid deformation"""
[docs] def __init__( self, point1, point2, amplitude=0.25, frequency=0.6, extras=0, invert=False, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): """Constructor.""" DecoratedLine.__init__( self, point1, point2, amplitude, frequency, extras, invert, "graviton", styles, arcthrupoint, is3D, arrows, labels, )
[docs] def getDeformedPath(self, sign=1): """Get the path with the decorative deformation.""" intwindings = int( self.frequency * pyx.unit.tocm(self.getVisiblePath().arclen()) / pyx.unit.tocm(self.arcradius) ) intwindings += self.extras sign *= 1 if self.inverted: sign *= -1 vispath = self.getVisiblePath() # TODO curveradius is not implemented in pyx 0.12 # curveradii = vispath.curveradius([i / 10.0 for i in range(0, 11)]) curveradii = [] mincurveradius = None for curveradius in curveradii: try: curveradius = abs(curveradius / pyx.unit.m) # if config.getOptions().DEBUG: # print self.__class__, "- curve radius = ", curveradius if mincurveradius is None or curveradius < mincurveradius: mincurveradius = curveradius except Exception: pass numhloopcurves = 5 if mincurveradius is not None: numhloopcurves += int(0.1 / mincurveradius) if config.getOptions().DEBUG: print( self.__class__, "- min curvature radius = ", mincurveradius, "->", numhloopcurves, "curves/hloop", ) defo = pyx.deformer.cycloid( self.arcradius, intwindings, curvesperhloop=numhloopcurves, skipfirst=0.0, skiplast=0.0, turnangle=0, sign=sign, ) return defo.deform(vispath)
[docs] def draw(self, canvas): """Draw the line on the supplied canvas.""" styles = self.styles + self.arrows if config.getOptions().DEBUG: print("Drawing " + str(self.__class__) + " with styles = " + str(styles)) mypath1 = self.getDeformedPath(+1) mypath2 = self.getDeformedPath(-1) if self.inverted: mypathtmp = mypath1 mypath1 = mypath2 mypath2 = mypathtmp if config.getOptions().DRAFT or not self.is3D: canvas.stroke(mypath1, styles) canvas.stroke(mypath2, styles) else: ass, bs = mypath1.intersect(mypath2) params1, params2 = [], [] parity1 = True if self.parity3D == 0: parity1 = False for a in ass[1:]: ## TODO: better endpoint cut vetoing if parity1: params1.append(a - self.skipsize3D) params1.append(a + self.skipsize3D) parity1 = not parity1 pathbits1 = mypath1.split(params1) on = True for pathbit in pathbits1: if on: canvas.stroke(pathbit, styles) on = not on parity2 = False if self.parity3D == 0: parity2 = True for b in bs[1:]: ## TODO: better endpoint cut vetoing if parity2: params2.append(b - self.skipsize3D) params2.append(b + self.skipsize3D) parity2 = not parity2 pathbits2 = mypath2.split(params2) on = True for pathbit in pathbits2: if on: canvas.stroke(pathbit, styles) on = not on for l in self.labels: l.draw(canvas)
[docs]class Gaugino(DecoratedLine): """A line with a sinoid deformation and a normal line"""
[docs] def __init__( self, point1, point2, amplitude=0.25, frequency=1.0, extras=0, invert=False, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): """Constructor.""" DecoratedLine.__init__( self, point1, point2, amplitude, frequency, extras, invert, "gaugino", styles, arcthrupoint, is3D, arrows, labels, )
[docs] def getDeformedPath(self, sign=1): """Get the path with the decorative deformation.""" intwindings = int( self.frequency * pyx.unit.tocm(self.getVisiblePath().arclen()) / pyx.unit.tocm(self.arcradius) ) intwindings += self.extras sign = 1 if self.inverted: sign = -1 vispath = self.getVisiblePath() # TODO curveradius is not implemented in pyx 0.12 # curveradii = vispath.curveradius([i / 10.0 for i in range(0, 11)]) curveradii = [] mincurveradius = None for curveradius in curveradii: try: curveradius = abs(mincurveradius / pyx.unit.m) # if config.getOptions().DEBUG: # print self.__class__, "- curvature radius = ", curveradius if mincurveradius is None or curveradius < mincurveradius: mincurveradius = curveradius except Exception: pass ## Use curvature info to increase number of curve sections numhloopcurves = 5 if mincurveradius is not None: numhloopcurves += int(0.1 / mincurveradius) if config.getOptions().DEBUG: print( self.__class__, "- min curve radius = ", mincurveradius, "->", numhloopcurves, "curves/hloop", ) defo = pyx.deformer.cycloid( self.arcradius, intwindings, curvesperhloop=numhloopcurves, skipfirst=0.0, skiplast=0.0, turnangle=0, sign=sign, ) return defo.deform(vispath)
[docs] def draw(self, canvas): """Draw the line on the supplied canvas.""" styles = self.styles + self.arrows if config.getOptions().DEBUG: print("Drawing " + str(self.__class__) + " with styles = " + str(styles)) mypath1 = self.getVisiblePath() mypath2 = self.getDeformedPath() if config.getOptions().DRAFT or not self.is3D: canvas.stroke(mypath1, styles) canvas.stroke(mypath2, styles) else: ass, bs = mypath1.intersect(mypath2) params1, params2 = [], [] parity1 = True if self.parity3D == 0: parity1 = False for a in ass: if parity1: params1.append(a - self.skipsize3D) params1.append(a + self.skipsize3D) parity1 = not parity1 pathbits1 = mypath1.split(params1) on = True for pathbit in pathbits1: if on: canvas.stroke(pathbit, styles) on = not on parity2 = False if self.parity3D == 0: parity2 = True for b in bs: if parity2: params2.append(b - self.skipsize3D) params2.append(b + self.skipsize3D) parity2 = not parity2 pathbits2 = mypath2.split(params2) on = True for pathbit in pathbits2: if on: canvas.stroke(pathbit, styles) on = not on for l in self.labels: l.draw(canvas)
[docs]class Gluino(DecoratedLine): """A line with a cycloid deformation and a normal line"""
[docs] def __init__( self, point1, point2, amplitude=0.25, frequency=1.2, extras=0, invert=False, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): """Constructor.""" DecoratedLine.__init__( self, point1, point2, amplitude, frequency, extras, invert, "susygluon", styles, arcthrupoint, is3D, arrows, labels, )
[docs] def getDeformedPath(self, sign=1): """Get the path with the decorative deformation.""" needwindings = ( self.frequency * pyx.unit.tocm(self.getVisiblePath().arclen()) / pyx.unit.tocm(self.arcradius) ) ## Get the whole number of windings and make sure that it's odd so we ## don't get a weird double-back thing intwindings = int(needwindings) intwindings += 2 * self.extras if intwindings % 2 == 0: intwindings -= 1 deficit = needwindings - intwindings sign = 1 if self.inverted: sign = -1 ## Get list of curvature radii in the visible path vispath = self.getVisiblePath() # TODO curveradius is deprecated in pyx 0.14 # curveradii = vispath.curveradius([i / 10.0 for i in range(0, 11)]) curveradii = [] mincurveradius = None ## Find the maximum curvature (set None if straight line) for curveradius in curveradii: try: curveradius = abs(self.curvature / pyx.unit.m) # if config.getOptions().DEBUG: # print self.__class__, "- curvature radius = ", curveradius if mincurveradius is None or curveradius < mincurveradius: mincurveradius = curveradius except: pass ## Use curvature info to increase number of curve sections numhloopcurves = 10 if mincurveradius is not None: numhloopcurves += int(0.2 / mincurveradius) if config.getOptions().DEBUG: print( self.__class__, "- min curve radius = ", mincurveradius, "->", numhloopcurves, "curves/hloop", ) defo = pyx.deformer.cycloid( self.arcradius, intwindings, curvesperhloop=numhloopcurves, skipfirst=0.0, skiplast=0.0, sign=sign, ) return defo.deform(vispath)
[docs] def draw(self, canvas): """Draw the line on the supplied canvas.""" styles = self.styles + self.arrows if config.getOptions().DEBUG: print("Drawing " + str(self.__class__) + " with styles = " + str(styles)) mypath1 = self.getVisiblePath() mypath2 = self.getDeformedPath() if config.getOptions().DRAFT or not self.is3D: canvas.stroke(mypath1, styles) canvas.stroke(mypath2, styles) else: ass, bs = mypath1.intersect(mypath2) params1, params2 = [], [] parity1 = True if self.parity3D == 0: parity1 = False for a in ass: if parity1: params1.append(a - self.skipsize3D) params1.append(a + self.skipsize3D) parity1 = not parity1 pathbits1 = mypath1.split(params1) on = True for pathbit in pathbits1: if on: canvas.stroke(pathbit, styles) on = not on parity2 = False if self.parity3D == 0: parity2 = True for b in bs: if parity2: params2.append(b - self.skipsize3D) params2.append(b + self.skipsize3D) parity2 = not parity2 para = pyx.deformer.parallel(0.001) _, sbs, _ = para.normpath_selfintersections( mypath2.normpath(), epsilon=0.01 ) coil_params = [] for b in sbs: coil_params.append(b[self.parity3D] - self.skipsize3D) coil_params.append(b[self.parity3D] + self.skipsize3D) params2 += coil_params params2.sort() pathbits2 = mypath2.split(params2) on = True for pathbit in pathbits2: if on: canvas.stroke(pathbit, styles) on = not on for l in self.labels: l.draw(canvas)
[docs]class Gravitino(DecoratedLine): """A line with a double sinoid deformation and a simple line"""
[docs] def __init__( self, point1, point2, amplitude=0.25, frequency=0.6, extras=0, invert=False, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): """Constructor.""" DecoratedLine.__init__( self, point1, point2, amplitude, frequency, extras, invert, "gravitino", styles, arcthrupoint, is3D, arrows, labels, )
[docs] def getDeformedPath(self, sign=1): """Get the path with the decorative deformation.""" intwindings = int( self.frequency * pyx.unit.tocm(self.getVisiblePath().arclen()) / pyx.unit.tocm(self.arcradius) ) intwindings += self.extras sign *= 1 if self.inverted: sign *= -1 vispath = self.getVisiblePath() # TODO curveradius is deprecated in pyx 0.14 # curveradii = vispath.curveradius([i / 10.0 for i in range(0, 11)]) curveradii = [] mincurveradius = None for curveradius in curveradii: try: curveradius = abs(curveradius / pyx.unit.m) # if config.getOptions().DEBUG: # print self.__class__, "- curve radius = ", curveradius if mincurveradius is None or curveradius < mincurveradius: mincurveradius = curveradius except: pass numhloopcurves = 5 if mincurveradius is not None: numhloopcurves += int(0.1 / mincurveradius) if config.getOptions().DEBUG: print( self.__class__, "- min curvature radius = ", mincurveradius, "->", numhloopcurves, "curves/hloop", ) defo = pyx.deformer.cycloid( self.arcradius, intwindings, curvesperhloop=numhloopcurves, skipfirst=0.0, skiplast=0.0, turnangle=0, sign=sign, ) return defo.deform(vispath)
[docs] def draw(self, canvas): """Draw the line on the supplied canvas.""" styles = self.styles + self.arrows if config.getOptions().DEBUG: print("Drawing " + str(self.__class__) + " with styles = " + str(styles)) mypath = [ self.getVisiblePath(), self.getDeformedPath(+1), self.getDeformedPath(-1), ] if self.inverted: mypath = mypath[::-1] if config.getOptions().DRAFT or not self.is3D: for i in range(3): canvas.stroke(mypath[i], styles) else: ass, bs = mypath[0].intersect(mypath[1]) ass, cs = mypath[0].intersect(mypath[2]) ps = [ass[:], bs[:], cs[:]] for i in range(3): params = [] for a in range(len(ps[i])): ## TODO: better endpoint cut vetoing if (a % 3) != i: params.append(ps[i][a] - self.skipsize3D) params.append(ps[i][a] + self.skipsize3D) pathbits = mypath[i].split(params) on = True for pathbit in pathbits: if on: canvas.stroke(pathbit, styles) on = not on for l in self.labels: l.draw(canvas)
[docs]class Phantom(DecoratedLine): """An invisible line."""
[docs] def __init__( self, point1, point2, amplitude=0.25, frequency=1.0, extras=0, invert=False, styles=None, arcthrupoint=None, is3D=False, arrows=None, labels=None, **kwargs ): """Constructor.""" DecoratedLine.__init__( self, point1, point2, amplitude, frequency, extras, invert, "phantom", styles, arcthrupoint, is3D, arrows, labels, )
[docs] def draw(self, canvas): """Draw the line on the supplied canvas (does nothing for a phantom apart from labels).""" for l in self.labels: l.draw(canvas) return
# A dictionary for mapping FeynML line types to line classes NamedLine = { "line": Line, "higgs": Scalar, "photon": Vector, "vector": Vector, "gluon": Gluon, "fermion": Line, "anti fermion": Line, "graviton": Graviton, "gaugino": Gaugino, "gluino": Gluino, "gravitino": Gravitino, "scalar": Scalar, "anti scalar": Scalar, "ghost": Ghost, "phantom": Phantom, "boson": Vector, }