Package pyfeyn :: Module lines
[hide private]
[frames] | no frames]

Source Code for Module pyfeyn.lines

  1  """Various particle line types.""" 
  2   
  3  import pyx, math 
  4  from pyx import color 
  5   
  6  from diagrams import FeynDiagram 
  7  from points import Point 
  8  from deco import Arrow, Label 
  9  from utils import Visible, defunit 
 10   
 11   
 12  ## Line base class 
13 -class Line(Visible):
14 "Base class for all objects which connect points in Feynman diagrams" 15
16 - def __init__(self, point1, point2):
17 self.p1 = point1 18 self.p2 = point2 19 self.styles = [] 20 self.arcthrupoint = None 21 self.is3D = False 22 self.arrows = [] 23 self.labels = [] 24 25 ## Add this to the current diagram automatically 26 FeynDiagram.currentDiagram.add(self)
27 28
29 - def addLabel(self, text, pos=0.5, displace=-0.25, angle = 0):
30 """Add a LaTeX label to this line, either via parameters or actually as 31 a TeXLable object.""" 32 if FeynDiagram.options.DEBUG: 33 print "Adding label: " + text 34 #if text.__class__ == "Label": 35 # self.labels.append(label) 36 #else: 37 self.labels.append(Label(text=text, line=self, pos=pos, displace=displace, angle=angle)) 38 if FeynDiagram.options.DEBUG: 39 print "Labels = " + str(self.labels) 40 return self
41 42
43 - def removeLabels(self):
44 self.labels = [] 45 return self
46 47
48 - def fracpoint(self, frac):
49 """Get a new Point representing the point at the given fraction along 50 the fundamental line (i.e. no truncation or deformation). 51 TODO: Handle units properly.""" 52 p = self.getPath() ## no truncation or deformation 53 x, y = p.at(p.begin() + frac * p.arclen()) 54 return Point(x/defunit, y/defunit)
55 56
57 - def setArrows(self, arrows):
58 ## TODO Check that the arg is a list 59 self.arrows = [] 60 for i in arrows: 61 if i.__class__ == "deco.Arrow": 62 self.arrows.append(i) 63 else: 64 self.arrows.append(Arrow(pos = i)) 65 return self
66 67
68 - def addArrow(self, position = 0.53, arrow = None):
69 """Add an arrow to the line at the specified position, which is a number 70 between 0 and 1, representing the fraction along the line at which the 71 arrow should be placed. The default arrow style can be overridden by 72 explicitly supplying an arrow object as the 'arrow' argument, in which 73 case the position argument will be ignored.""" 74 if arrow: 75 self.arrows.append(arrow) 76 else: 77 self.arrows.append(Arrow(pos=position)) 78 return self
79 80
81 - def removeArrows(self):
82 """Remove all arrows from this line.""" 83 self.arrows = [] 84 return self
85 86
87 - def arcThru(self, arcpoint = None, x = None, y = None):
88 """Set the point through which this line will arc. Either pass a Point 89 or set x, y as floats.""" 90 if arcpoint != None: 91 self.arcthrupoint = arcpoint 92 elif x != None and y != None: 93 self.arcthrupoint = Point(x, y) 94 else: 95 raise Exception("Tried to set an arcpoint with invalid arguments") 96 return self
97 98
99 - def straighten(self):
100 """Make this line a straight line between start and end.""" 101 self.arcthrupoint = None
102 103
104 - def bend(self, amount):
105 """Bend the line to the right by a given distance.""" 106 middle = self.p1.midpoint(self.p2) 107 nx = (middle.y() - self.p1.y()) / abs(self.p1.distance(middle)) 108 ny = (self.p1.x() - middle.x()) / abs(self.p1.distance(middle)) 109 vx = middle.x() - self.p1.x() 110 vy = middle.y() - self.p1.y() 111 if (vx * ny - vy * nx) > 0: 112 nx *= -1 113 ny *= -1 114 arcpoint = Point(middle.x() + amount * nx, middle.y() + amount * ny) 115 if FeynDiagram.options.VDEBUG: 116 FeynDiagram.currentCanvas.stroke( 117 pyx.path.line(middle.x(), middle.y(), arcpoint.x(), arcpoint.y()), [color.rgb.blue] ) 118 self.arcThru(arcpoint) 119 if FeynDiagram.options.DEBUG: 120 print self.getVisiblePath() 121 if FeynDiagram.options.VDEBUG: 122 FeynDiagram.currentCanvas.stroke(self.getVisiblePath(), [color.rgb.blue]) 123 return self
124 125
126 - def set3D(self, choice):
127 self.is3D = choice 128 return self
129 130
131 - def getStyles(self, stylelist):
132 return self.styles
133 134
135 - def setStyles(self, stylelist):
136 self.styles = stylelist 137 return self
138 139
140 - def addStyle(self, style):
141 self.styles.append(style) 142 return self
143 144
145 - def addStyles(self, stylelist):
146 self.styles = self.styles + stylelist 147 return self
148 149
150 - def getPath(self):
151 if self.arcthrupoint == None: 152 ## This is a simple straight line 153 return pyx.path.path( pyx.path.moveto( *(self.p1.getXY()) ), 154 pyx.path.lineto( *(self.p2.getXY()) ) ) 155 elif (self.p1.x() == self.p2.x() and self.p1.y() == self.p2.y()): 156 ## This is a tadpole-type loop and needs special care; 157 ## We shall assume that the arcthrupoint is meant to be 158 ## the antipode of the basepoint 159 arccenter = self.p1.midpoint(self.arcthrupoint) 160 arcradius = self.p1.distance(self.arcthrupoint) / 2.0 161 162 ## TODO Why does a circle work and an arc doesn't? 163 cargs = (arccenter.x(), arccenter.y(), arcradius) 164 circle = pyx.path.circle(*cargs) 165 line = pyx.path.line( self.p1.x(), self.p1.y(), arccenter.x(), arccenter.y()) 166 if FeynDiagram.options.VDEBUG: 167 FeynDiagram.currentCanvas.stroke(line, [color.rgb.green]) 168 as, bs = circle.intersect(line) 169 subpaths = circle.split(as[0]) 170 cpath = subpaths[0] 171 return cpath 172 173 ## or, with an arc... 174 arcangle1 = arccenter.arg(self.p1) 175 arcangle2 = arccenter.arg(self.p1) + 360 176 arcargs = (arccenter.x(), arccenter.y(), arcradius, arcangle1, arcangle2) 177 return pyx.path.path( pyx.path.arc(*arcargs) ) 178 179 else: 180 n13, n23 = None, None 181 ## Work out line gradients 182 try: 183 n13 = (self.p1.y() - self.arcthrupoint.y()) / (self.p1.x() - self.arcthrupoint.x()) 184 except ZeroDivisionError: 185 if FeynDiagram.options.DEBUG: 186 print "Grad 1 diverges" 187 n13 = 1e100 188 189 try: 190 n23 = (self.p2.y() - self.arcthrupoint.y()) / (self.p2.x() - self.arcthrupoint.x()) 191 except ZeroDivisionError: 192 if FeynDiagram.options.DEBUG: 193 print "Grad 2 diverges" 194 n23 = 1e100 195 196 ## If gradients match, 197 ## then we have a straight line, so bypass the complexity 198 if n13 == n23: 199 return pyx.path.path( pyx.path.moveto(*(self.p1.getXY())), 200 pyx.path.lineto(*(self.p2.getXY())) ) 201 202 ## Otherwise work out conjugate gradients and midpoints 203 m13, m23 = None, None 204 try: 205 m13 = -1.0 / n13 206 except ZeroDivisionError: 207 m13 = 1e100 208 try: 209 m23 = -1.0 / n23 210 except ZeroDivisionError: 211 m23 = 1e100 212 mid13 = self.p1.midpoint(self.arcthrupoint) 213 mid23 = self.p2.midpoint(self.arcthrupoint) 214 215 ## Line y-intercepts 216 c13 = mid13.y() - m13 * mid13.x() 217 c23 = mid23.y() - m23 * mid23.x() 218 219 ## Find the centre of the arc 220 xcenter = - (c23 - c13) / (m23 - m13) 221 ycenter = m13 * xcenter + c13 222 arccenter = Point(xcenter, ycenter) 223 224 ## Get the angles required for drawing the arc 225 arcradius = arccenter.distance(self.arcthrupoint) 226 arcangle1 = arccenter.arg(self.p1) 227 arcangle2 = arccenter.arg(self.p2) 228 arcangle3 = arccenter.arg(self.arcthrupoint) 229 arcargs = (arccenter.x(), arccenter.y(), arcradius, arcangle1, arcangle2) 230 231 if FeynDiagram.options.DEBUG and arcangle1 == arcangle2: 232 print "Arc angles are the same - not drawing anything" 233 234 ## Calculate cross product to determine direction of arc 235 vec12 = [self.p2.x()-self.p1.x(), self.p2.y()-self.p1.y(), 0.0] 236 vec13 = [self.arcthrupoint.x()-self.p1.x(), self.arcthrupoint.y()-self.p1.y(), 0.0] 237 crossproductZcoord = vec12[0]*vec13[1] - vec12[1]*vec13[0] 238 239 if crossproductZcoord < 0: 240 return pyx.path.path( pyx.path.moveto(*(self.p1.getXY())), 241 pyx.path.arc(*arcargs)) 242 else: 243 return pyx.path.path( pyx.path.moveto(*(self.p1.getXY())), 244 pyx.path.arcn(*arcargs))
245 246
247 - def getVisiblePath(self):
248 """Find the subpath between the endpoints which isn't overshadowed by a blob of some kind""" 249 p1path = self.p1.getPath() 250 p2path = self.p2.getPath() 251 vispath = self.getPath() 252 if FeynDiagram.options.VDEBUG: 253 FeynDiagram.currentCanvas.stroke(vispath, [color.rgb.green]) 254 if p1path: 255 as, bs = p1path.intersect(vispath) 256 for b in bs: 257 subpaths = vispath.split(b) 258 if len(subpaths) > 1: 259 if FeynDiagram.options.DEBUG: 260 print "Num subpaths 1 = %d" % len(subpaths) 261 subpaths.sort( lambda x, y : int(pyx.unit.tocm(x.arclen() - y.arclen())/math.fabs(pyx.unit.tocm(x.arclen() - y.arclen()))) ) 262 vispath = subpaths[-1] 263 if FeynDiagram.options.VDEBUG: 264 FeynDiagram.currentCanvas.stroke(subpaths[0], [color.rgb.blue]) 265 if FeynDiagram.options.VDEBUG: 266 for a in as: 267 ix, iy = p1path.at(a) 268 FeynDiagram.currentCanvas.fill(pyx.path.circle(ix, iy, 0.05), [color.rgb.green]) 269 if p2path: 270 as, bs = p2path.intersect(vispath) 271 for b in bs: 272 subpaths = vispath.split(b) 273 if len(subpaths) > 1: 274 if FeynDiagram.options.DEBUG: 275 print "Num subpaths 2 = %d" % len(subpaths) 276 subpaths.sort( lambda x, y : int(pyx.unit.tocm(x.arclen() - y.arclen())/math.fabs(pyx.unit.tocm(x.arclen() - y.arclen()))) ) 277 vispath = subpaths[-1] 278 if FeynDiagram.options.VDEBUG: 279 FeynDiagram.currentCanvas.stroke(subpaths[0], [color.rgb.red]) 280 if FeynDiagram.options.VDEBUG: 281 for a in as: 282 ix, iy = p2path.at(a) 283 FeynDiagram.currentCanvas.fill(pyx.path.circle(ix, iy, 0.05), [color.rgb.blue]) 284 if FeynDiagram.options.VDEBUG: 285 FeynDiagram.currentCanvas.stroke(vispath, [color.rgb.red]) 286 #return pyx.path.circle(-2,-1,0.2) 287 return vispath
288 289
290 - def draw(self, canvas):
291 path = self.getVisiblePath() 292 styles = self.styles + self.arrows 293 if FeynDiagram.options.DEBUG: 294 print "Drawing " + str(self.__class__) + " with styles = " + str(styles) 295 print path 296 canvas.stroke(path, styles) 297 for l in self.labels: 298 l.draw(canvas)
299 300
301 -class Fermion(Line):
302 pass
303 304
305 -class Scalar(Line):
306 - def draw(self, canvas):
307 path = self.getVisiblePath() 308 styles = self.styles + [pyx.style.linestyle.dashed] + self.arrows 309 ## TODO: call base class method? 310 if FeynDiagram.options.DEBUG: 311 print "Drawing " + str(self.__class__) + " with styles = " + str(styles) 312 print path 313 canvas.stroke(path, styles) 314 for l in self.labels: 315 l.draw(canvas)
316 317
318 -class Higgs(Scalar):
319 pass
320 321 322 323 ## DecoratedLine base class
324 -class DecoratedLine(Line):
325 """Base class for spring and sine-like lines"""
326 - def invert(self):
327 pass
328
329 - def numHalfPeriods(self):
330 pass
331
332 - def strikeThru(self):
333 pass
334
335 - def getDeformedPath(self):
336 return getVisiblePath()
337 338
339 -class Gluon(DecoratedLine):
340 """A line with a cycloid deformation"""
341 - def __init__(self, point1, point2):
342 self.p1 = point1 343 self.p2 = point2 344 self.styles = [] 345 self.arcthrupoint = None 346 self.is3D = False 347 self.arrows = [] 348 self.labels = [] 349 self.arcradius = pyx.unit.length(0.25) 350 self.elasticity = 1.3 351 self.inverted = False 352 self.linetype = "gluon" 353 ## Add this to the current diagram automatically 354 FeynDiagram.currentDiagram.add(self)
355 356
357 - def invert(self):
358 self.inverted = not self.inverted 359 return self
360 361
362 - def getTension(self):
363 return self.elasticity
364 365
366 - def setTension(self, value):
367 self.elasticity = value 368 return self
369 370
371 - def getDeformedPath(self):
372 needwindings = self.elasticity * \ 373 pyx.unit.tocm(self.getVisiblePath().arclen()) / pyx.unit.tocm(self.arcradius) 374 ## Get the whole number of windings and make sure that it's odd so we 375 ## don't get a weird double-back thing 376 intwindings = int(needwindings) 377 if intwindings % 2 == 0: 378 intwindings -= 1 379 deficit = needwindings - intwindings 380 sign = 1 381 if self.inverted: sign = -1 382 defo = pyx.deformer.cycloid(self.arcradius, intwindings, curvesperhloop=10, skipfirst = 0.0, skiplast = 0.0, sign = sign) 383 return defo.deform(self.getVisiblePath())
384 385
386 - def draw(self, canvas):
387 styles = self.styles + self.arrows 388 if FeynDiagram.options.DEBUG: 389 print "Drawing " + str(self.__class__) + " with styles = " + str(styles) 390 canvas.stroke(self.getDeformedPath(), styles) 391 for l in self.labels: 392 l.draw(canvas)
393 394 395
396 -class Vector(DecoratedLine):
397 """A line with a sinoid deformation"""
398 - def __init__(self, point1, point2):
399 self.p1 = point1 400 self.p2 = point2 401 self.styles = [] 402 self.arcthrupoint = None 403 self.is3D = False 404 self.arrows = [] 405 self.labels = [] 406 self.inverted = False 407 self.arcradius = pyx.unit.length(0.25) 408 self.linetype = "photon" 409 ## Add this to the current diagram automatically 410 FeynDiagram.currentDiagram.add(self)
411 412
413 - def invert(self):
414 self.inverted = not self.inverted 415 return self
416 417
418 - def getDeformedPath(self):
419 intwindings = int(1.0 * pyx.unit.tocm(self.getVisiblePath().arclen()) / pyx.unit.tocm(self.arcradius)) 420 sign = 1 421 if self.inverted: sign = -1 422 defo = pyx.deformer.cycloid(self.arcradius, intwindings, curvesperhloop=5, skipfirst=0.0, skiplast=0.0, turnangle=0, sign=sign) 423 return defo.deform(self.getVisiblePath())
424 425
426 - def draw(self, canvas):
427 styles = self.styles + self.arrows 428 if FeynDiagram.options.DEBUG: 429 print "Drawing " + str(self.__class__) + " with styles = " + str(styles) 430 canvas.stroke(self.getDeformedPath(), styles) 431 for l in self.labels: 432 l.draw(canvas)
433 434
435 -class Photon(Vector):
436 pass
437 438 439 # A dictionary for mapping FeynML line types to line classes 440 NamedLine = {"photon" : Photon, "gluon" : Gluon, "fermion" : DecoratedLine} 441