Created
December 19, 2011 15:26
-
-
Save dekosuke/1497676 to your computer and use it in GitHub Desktop.
ファインマンダイアグラム描くよ draw feynman diagram
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#hogehoge/python | |
# coding=utf-8 | |
#ファインマンダイアグラムの描画 | |
#ファインマンダイアグラムについては、fetter-waleckaの本を参照 | |
# | |
#内容 | |
#・ファインマンダイアグラムの計算(文字情報。\latex形式に出力可能) | |
#・計算したダイアグラムデータのベクトル画像化(ベクトル画像情報。できれば.ai形式に) | |
#・ベクトル画像化したダイアグラムデータのpng(gif?)画像化 | |
#ぐらい | |
#必要な非標準モジュール | |
#・psyco(なくても構わない) | |
#必要な環境 | |
#SVGが閲覧できるブラウザ(firefoxなど。IEもプラグインを導入すれば見られる) | |
#改良案: | |
#・ダイアグラム生成アルゴリズムの改良(あまり速度には貢献しないが・・・) | |
#・svg->png変換→batikなるものが。いずれにしろ面倒なので後回し | |
##・proper/improperで分類 | |
##・いろいろな近似(partial sum)に対応 | |
#・いくつかの関数(getdiagramとgetBigDiagramみたいな)は統一すべし | |
#巨大svgファイルのオプションについて | |
HEIGHT_DEF=300 | |
FRAMEHEIGHT_DEF=50 | |
FRAMEWIDTH_DEF=50 | |
ALLHEIGHT_DEF=HEIGHT_DEF+FRAMEHEIGHT_DEF*2 | |
#ALLWIDTH_DEF=WIDTH_DEF+FRAMEWIDTH_DEF*2 | |
#WIDTHが非確定なのは大きな問題だ・・・ | |
#始点か終点か判定 | |
#2文字目がfなら始点、tなら終点 | |
def isEnd(astr): | |
if astr[1]=="f": | |
return False | |
elif astr[1]=="t": | |
return True | |
else: | |
print "unexpected string :",astr | |
return | |
def isStart(astr): | |
if astr[1]=="f": | |
return True | |
elif astr[1]=="t": | |
return False | |
else: | |
print "unexpected string :",astr | |
return | |
#ブロック生成 | |
def createBlock(n): | |
n=str(n) | |
ret=[] | |
ret.append("xf" +n) | |
ret.append("xt" +n) | |
ret.append("xfd"+n) | |
ret.append("xtd"+n) | |
return ret | |
#ブロック生成(終点無し版) | |
def createBlockf(n): | |
n=str(n) | |
ret=[] | |
ret.append("xf" +n) | |
ret.append("xfd"+n) | |
ret.append("xtd"+n) | |
return ret | |
#ブロック生成(始点無し版) | |
def createBlockt(n): | |
n=str(n) | |
ret=[] | |
ret.append("xt" +n) | |
ret.append("xfd"+n) | |
ret.append("xtd"+n) | |
return ret | |
#項(線)のlatexの数学記号化 | |
#iG^0(y^\prime_1,x) | |
#みたいな | |
def toLatex(aline): | |
rstart=aline[0][0] | |
if len(aline[0])>2: | |
if aline[0][2]=="d": | |
rstart+="^\prime" | |
rstart+="_"+aline[0][-1] | |
rend=aline[1][0] | |
if len(aline[1])>2: | |
if aline[1][2]=="d": | |
rend+="^\prime" | |
rend+="_"+aline[1][-1] | |
return "iG^0("+rend+","+rstart+")" | |
#t(終点)からf(始点)に | |
import string | |
def TToFconv(astr): | |
return string.replace(astr,"t","f") | |
# | |
#ファインマンダイアグラム作成(視覚化) | |
# | |
#ダイアグラムをメインライン(y->x)とループのリストに分解 | |
def decompose(nodes, alines, wavelines=[]): | |
lines=[] | |
#alinesの記号からt,fを抜いたものがlines | |
for i in range(len(alines)): | |
#lines.append([]) | |
a=string.replace(alines[i][0],"f","") | |
a=string.replace(a,"t","") | |
b=string.replace(alines[i][1],"f","") | |
b=string.replace(b,"t","") | |
lines.append([a,b]) | |
#print alines,lines | |
#まず、yからxへの経路を検出 | |
mainpath=[] | |
nowNode=lines[0][0] #yf | |
mainpath.append(nowNode) | |
if nowNode!="y": | |
print "unexpected start node!",lines | |
return | |
while nowNode!="x": | |
for i in range(len(lines)): | |
if lines[i][0]==nowNode: #線が見つかった | |
mainpath.append(lines[i][1]) | |
nowNode=lines[i][1] | |
del(lines[i]) | |
break | |
else: #線が切れている場合 | |
print "disconnected main line",lines | |
return | |
#次に各ループを検出 | |
if len(lines)==0: #ループ無し | |
return (mainpath, []) | |
loops=[] | |
loops.append([]) | |
#print "lines=",lines | |
loopStart=lines[0][0] #ループ始点 | |
nowNode=lines[0][0] | |
while True: #線が残っている場合 | |
for i in range(len(lines)): | |
if lines[i][0]==nowNode: | |
loops[-1].append(nowNode) | |
nowNode=lines[i][1] | |
del(lines[i]) | |
if nowNode==loopStart: #ループが閉じた | |
if len(lines)>0: | |
loopStart=lines[0][0] | |
nowNode=loopStart | |
loops.append([]) | |
else: | |
return (mainpath, loops) | |
break | |
print "unexpected end" | |
# | |
#ある記号と共役な記号を返す | |
#ようするにx1の共役はxd1(逆も然り)で、xの共役はy | |
#xとyを除く共役な2点はwavy lineで結ばれる | |
def conjugate(aline): | |
#print aline | |
if aline=="x": | |
return "y" | |
elif aline=="y": | |
return "x" | |
elif aline[1]=="d": | |
return aline[0]+aline[2] | |
elif len(aline)==2: | |
return aline[0]+"d"+aline[1] | |
else: | |
print "unexpected symbol in conjugate()",aline | |
def mean(a,b): | |
return (a+b)/2 | |
def bigger(a,b): | |
if a>b: | |
return a | |
else: | |
return b | |
def slide(aline, n): | |
return aline[n:]+aline[:n] | |
def revslide(aline, n): | |
return aline[-n:]+aline[:-n] | |
#位置クラス。xとyのみ | |
class Pos: | |
def __init__(self, x,y): | |
self.x=x | |
self.y=y | |
def __add__(self, arg): | |
#新しい位置インスタンスを作成して返す | |
if isinstance(arg, Pos): | |
ret=Pos( arg.x+self.x, arg.y+self.y ) | |
return ret | |
elif isinstance(arg, tuple): | |
ret=Pos( self.x+arg[0], self.y+arg[1] ) | |
return ret | |
else: | |
#print arg | |
raise PositionError,"Unexpected type for __add__ operation.",arg #例外出す | |
def __radd__(self, arg): | |
#print "self=",self | |
#print "arg=",arg | |
return self.__add__(arg) | |
def __iadd__(self, arg): | |
self.x+=arg.x | |
self.y+=arg.y | |
return self | |
def __mul__(self, arg): | |
ret=Pos( self.x*arg, self.y*arg ) #スカラー倍 | |
return ret | |
def __div__(self, arg): | |
ret=Pos( self.x/arg, self.y/arg ) | |
return ret | |
def __imul__(self, arg): | |
if isinstance(arg, float) or isinstance(arg,int): #スカラー倍 | |
self.x*=arg | |
self.y*=arg | |
else: | |
raise PositionError,"Unexpected type for __imul__ operation." #例外出す | |
def __idiv__(self, arg): | |
if isinstance(arg, float) or isinstance(arg,int): #スカラー倍 | |
self.x/=arg | |
self.y/=arg | |
else: | |
raise PositionError,"Unexpected type for __imul__ operation." #例外出す | |
def __repr__(self): | |
return "Pos"+str( (self.x, self.y) ) | |
def distance(self, apos): | |
d2=(self.x-apos.x)**2+(self.y-apos.y)**2 | |
return d2**0.5 | |
OBJ_LINE=0 | |
OBJ_CIRCLE=1 | |
OBJ_POINT=2 | |
OBJ_DLINE=3 | |
OBJ_WLINE=4 | |
OBJ_WCIRCLE=5 | |
#placeの戻り値で描画する画像の単位なクラス | |
#x,y型の位置にはPos型を利用 | |
#型それぞれで継承したほうがいいとかいうことはキニシナイ | |
class VecObj: | |
def __init__(self, *args): | |
self.type=args[0] | |
if self.type==OBJ_LINE: | |
self.f=copy.deepcopy(args[1]) | |
self.t=copy.deepcopy(args[2]) | |
elif self.type==OBJ_CIRCLE: | |
self.x=copy.deepcopy(args[1]) #中心位置 | |
self.rad=args[2] #半径 | |
self.args=copy.deepcopy(args[3]) #左のargsは(円の中の点の)角度で、右のargsは引数(笑) | |
elif self.type==OBJ_POINT: | |
self.x=copy.deepcopy(args[1]) | |
self.symbol=args[2] #記号。yとかxとかx2とかx3dとかの文字列。 | |
elif self.type==OBJ_DLINE: | |
pass #未実装 | |
elif self.type==OBJ_WLINE: #データ構造的には普通の線と同じ | |
self.f=copy.deepcopy(args[1]) | |
self.t=copy.deepcopy(args[2]) | |
elif self.type==OBJ_WCIRCLE: | |
#2点を結ぶ破線 | |
#データ構造的には普通の線と同じ→右周りか左周りかの情報をつけるようになった | |
self.f=copy.deepcopy(args[1]) | |
self.t=copy.deepcopy(args[2]) | |
if len(args)>3: #回る方向。初期化後の代入でもいい | |
self.rightRot=copy.deepcopy(args[3]) | |
def __repr__(self): | |
if self.type==OBJ_LINE: | |
typeStr="LINEOBJECT " | |
elif self.type==OBJ_CIRCLE: | |
typeStr="CIRCLEOBJECT " | |
elif self.type==OBJ_POINT: | |
typeStr="POINTOBJECT " | |
elif self.type==OBJ_DLINE: | |
typeStr="DLINEOBJECT " | |
elif self.type==OBJ_WLINE: | |
typeStr="WAVYLINEOBJECT " | |
elif self.type==OBJ_WCIRCLE: | |
typeStr="WAVYCIRCLEOBJECT " | |
return typeStr+str( vars(self) ) | |
def translate(self, m ): #mはPos型 | |
#print "self=",self | |
#print "m=",m | |
if hasattr(self, "f"): | |
self.f+=m | |
if hasattr(self, "t"): | |
self.t+=m | |
if hasattr(self,"x"): | |
self.x+=m | |
def lineartransform(mat): | |
#線形変換 | |
if hasattr(self, "f"): | |
self.f.x,self.f.y=mat[0][0]*self.f.x+mat[0][1]*self.f.y,mat[1][0]*self.f.x+mat[1][1]*self.f.y | |
if hasattr(self, "t"): | |
self.t.x,self.t.y=mat[0][0]*self.t.x+mat[0][1]*self.t.y,mat[1][0]*self.t.x+mat[1][1]*self.t.y | |
if hasattr(self,"x"): | |
self.x,self.y=mat[0][0]*self.x+mat[0][1]*self.y,mat[1][0]*self.x+mat[1][1]*self.y | |
def rotate(arg): | |
#位置情報の回転だけじゃなく、circleの場合は角度も変える必要があるな・・・ | |
pass | |
def positions(): | |
#円専用。構成している点の座標のリストを(argsから計算して)返す | |
pass | |
def __str__(self): | |
return self.__repr__() | |
import math | |
circleRatio=0.7/math.pi #ダイアグラムの円(1-ループの大きさ)の、単位線に対する大きさの比 | |
distanceRatio=0.5 #円を作成するときの左側との間隔(の単位線に対する大きさの比) | |
oneSizeLoopRatio=0.7 #1つだけの円の大きさにかける係数 | |
#circSizeRatio=0.7 #出現部分参照 | |
#ダイアグラムの各要素の描画位置(と大きさ)を決定 | |
#縦の長さ(height)は固定、横の長さは固定されていない | |
#返り値はheight, width, objects | |
def place(lineAndLoops, height=HEIGHT_DEF, frameHeight=FRAMEHEIGHT_DEF*2, frameWidth=FRAMEWIDTH_DEF*2): | |
global circleRatio | |
objects=[] #返り値 | |
mainline=lineAndLoops[0] | |
loops=lineAndLoops[1] | |
#positionsは位置のハッシュ | |
positions={} | |
#ループのほうは各点の位置の他に、円の情報が必要 | |
circleSpec=[] | |
#mainlineの各点の位置設定 | |
for i in range(len(mainline)): | |
elem=mainline[i] | |
positions[elem]=Pos( frameWidth/2, height*(len(mainline)-i-1)/(len(mainline)-1) + frameHeight/2 ) | |
#メイン線を追加 | |
num=len(mainline)-1 #メイン線の分割数 | |
for i in range(num): | |
objects.append( VecObj(OBJ_LINE, Pos(frameWidth/2,height*(i+1)/float(num)+frameHeight/2), Pos(frameWidth/2,height*i/float(num)+frameHeight/2) ) ) | |
maincomp=copy.deepcopy(mainline) #mainline+既に位置の決定されたループ(後で追加)の連結成分 | |
#基準とする大きさ。mainlineの一つの線の長さ | |
unitLine=height/(len(mainline)-1) | |
#それぞれのループの位置を決定していく | |
for i in range(len(loops)): | |
#最初にループの各点に対する共役点がmaincompに存在するかどうか探す | |
mainMatchList=[] | |
for elem in loops[i]: | |
cond=conjugate(elem) | |
#print "cond=",cond | |
if cond in maincomp: | |
#mainloop中に見つかった | |
mainMatchList.append(elem) | |
mainMatchNum=len(mainMatchList) | |
#ループの位置と形を決定する。 | |
#ループの要素数とmaincompとの共役点の数の組で場合分けして処理する | |
loopSize=len(loops[i]) | |
if loopSize==1: | |
if mainMatchNum==1: | |
cond=conjugate(loops[i][0]) | |
basePos=positions[cond] | |
positions[loops[i][0]]=basePos+Pos(unitLine*distanceRatio, 0) #1-loop円のポジションは円の左端 | |
circRad=unitLine*circleRatio*oneSizeLoopRatio | |
circleSpec.append( ([math.pi,], basePos+Pos(unitLine*(distanceRatio)+circRad,0)\ | |
, circRad) ) #円の形指定。(円を構成するループ各点の角度、中心座標、半径)のタプル | |
#maincomp.append(loops[i][0]) | |
else: #ダイアグラム生成のアルゴリズム上たぶんありえない筈だが・・・ | |
print "error: disconnected loop!" | |
return | |
elif loopSize==2: | |
if mainMatchNum==2: #2-2ループ | |
cond1=conjugate(loops[i][0]) | |
cond2=conjugate(loops[i][1]) | |
basePoses=[] | |
basePoses.append(positions[cond1]) | |
basePoses.append(positions[cond2]) | |
if basePoses[0].y<basePoses[1].y: | |
upper=0 #上にある点 | |
else: | |
upper=1 | |
if basePoses[0].x>basePoses[1].x: | |
right=0 #右にある点 | |
else: | |
right=1 | |
circRad=abs(basePoses[1].y-basePoses[0].y)/2 | |
positions[loops[i][0]]=Pos(basePoses[right].x+unitLine*distanceRatio+circRad, basePoses[0].y) | |
positions[loops[i][1]]=Pos(basePoses[right].x+unitLine*distanceRatio+circRad, basePoses[1].y) | |
if upper==0: | |
args=[math.pi/2,3*math.pi/2] | |
else: | |
args=[3*math.pi/2,math.pi/2] #普通こっちの筈 | |
circleSpec.append( (args, Pos(positions[loops[i][0]].x, (basePoses[0].y+basePoses[1].y)/2),\ | |
circRad) )#円の形指定。(円を構成するループ各点の角度、中心座標、半径)のタプル | |
elif mainMatchNum==1: #2-1ループ | |
cond1=conjugate(loops[i][0]) | |
positions[loops[i][0]]=positions[cond1]+Pos(unitLine*distanceRatio, 0) | |
positions[loops[i][1]]=positions[cond1]+Pos( unitLine*(distanceRatio+2*circleRatio),0 ) | |
args=[math.pi,0.0] | |
#Pos( (positions[loops[i][0]].x+positions[loops[i][1]].x)/2, positions[loops[i][0]].y)\ #下の行の変更前 | |
circleSpec.append( (args, (positions[loops[i][0]]+positions[loops[i][1]])/2.0\ | |
, unitLine*circleRatio) )#円の形指定。(円を構成するループ各点の角度、中心座標、半径)のタプル | |
else: #ダイアグラム生成のアルゴリズム上たぶんありえない筈だが・・・ | |
print "error: disconnected loop!" | |
return | |
else: #一般的な場合。個別の場合以外の処理 | |
if mainMatchNum==1: | |
basePos=positions[conjugate(mainMatchList[0])] #基準点 | |
circRad=unitLine*circleRatio*(loopSize-2) #円の半径 | |
circCenter=basePos+Pos(unitLine*distanceRatio+circRad,0) #中心点 | |
cpIndex=loops[i].index(mainMatchList[0]) #連結点の番号 | |
newLoop=slide(loops[i],cpIndex) | |
#連結される点は180度の位置に行くが、他の点は90度から-90度に均等に配置 | |
args=[] | |
for j in range(loopSize-1): | |
args.append( math.asin(1-2.0*j/(loopSize-2)) ) | |
argList=[math.pi,]+copy.deepcopy(args) | |
#回転 | |
argList=revslide(argList,cpIndex) | |
positions[mainMatchList[0]]=circCenter+Pos( circRad*math.cos(math.pi), -circRad*math.sin(math.pi) ) | |
for j in range(len(args)): | |
positions[newLoop[j+1]]=circCenter+Pos( circRad*math.cos(args[j]),-circRad*math.sin(args[j]) ) | |
circleSpec.append( (argList, circCenter, circRad) ) | |
elif mainMatchNum>1: | |
#その他。最も一般的なパターンだが、3次以上の高次の項にて出てくる | |
#1/1,2/1,2/2,n/1以外は全てこれに | |
#メイン部分との結合がある点の中で、最も低い位置と最も高い位置にいる点を探す(円の大きさを決定するのに必要) | |
lowest=height+frameHeight #初期化 | |
lowref=0 #一番上の点 | |
highest=0 | |
right=0 #最も右側 | |
for elem in mainMatchList: | |
#elem=mainMatchList[j] | |
cond=conjugate(elem) | |
if positions[cond].y<lowest: | |
lowest=positions[cond].y | |
lowref=loops[i].index(elem) #elemの番号 | |
if positions[cond].y>highest: | |
highest=positions[cond].y | |
if positions[cond].x>right: | |
right=positions[cond].x | |
#円の位置の決定 | |
#basePos=right+unitLine*distanceRatio,mean(lowest,highest) #円左端 | |
circRad=bigger( (highest-lowest)/2.0 , unitLine*(loopSize-mainMatchNum-1)/2 )#半径 | |
circCenter=Pos( right+unitLine*distanceRatio+circRad,mean(lowest,highest) ) #中心 | |
#一番上の点を上端(90度)にあわせて、残りを適当に配置 | |
argDif=2*math.pi/loopSize | |
#ループを円順にずらす(90度の点が最初になるようにする) | |
newloop=slide(loops[i],lowref) | |
#print "newloop=",newloop | |
args=[] | |
argList={} | |
for j in range(loopSize): | |
args.append(math.pi/2-argDif*j) | |
argList[newloop[j]]=args[-1] | |
positions[newloop[j]]=circCenter+Pos( circRad*math.cos(args[-1]), -circRad*math.sin(args[-1]) ) | |
newArgs=[] | |
for j in range(loopSize): | |
newArgs.append(argList[loops[i][j]]) | |
circleSpec.append( ( newArgs, circCenter, circRad) ) | |
pass | |
else: #ダイアグラム生成のアルゴリズム上たぶんありえない筈だが・・・ | |
print "error: disconnected loop!" | |
return | |
for elem in loops[i]: | |
maincomp.append(elem) #ループを連結リストに追加 | |
for j in range(len(circleSpec)): | |
objects.append( VecObj(OBJ_CIRCLE, circleSpec[j][1],circleSpec[j][2], circleSpec[j][0]) ) #円を追加 | |
for point in maincomp: | |
objects.append( VecObj(OBJ_POINT, positions[point],point) ) #点を追加 | |
width=100 | |
for j in range(len(circleSpec)): #横の大きさ検出 | |
#print circleSpec | |
if circleSpec[j][1].x+circleSpec[j][2] > width: | |
width=circleSpec[j][1].x+circleSpec[j][2] | |
#波線を追加 | |
for key in positions.keys(): | |
if len(key)==3: | |
if (key in mainline) and (conjugate(key) in mainline): | |
#両方ともメイン線上にあるとメイン線とかぶるので曲線になる | |
objects.append( VecObj(OBJ_WCIRCLE, positions[conjugate(key)],positions[key]) ) | |
else: | |
objects.append( VecObj(OBJ_WLINE, positions[conjugate(key)],positions[key]) ) | |
#波半円の左右の並べ方アルゴリズム | |
#衝突の少ない側(同じ衝突数なら右)に並ぶ | |
def iscoll(aobj, bobj): | |
bigs=[] | |
smls=[] | |
bigs.append( max(aobj.f.y,aobj.t.y) ) | |
smls.append( min(aobj.f.y,aobj.t.y) ) | |
bigs.append( max(bobj.f.y,bobj.t.y) ) | |
smls.append( min(bobj.f.y,bobj.t.y) ) | |
if bigs[0]>bigs[1]: | |
bigger=0 | |
smaller=1 | |
else: | |
bigger=1 | |
smaller=0 | |
if smls[bigger]<bigs[smaller] and smls[bigger]>smls[smaller]: | |
return True | |
else: | |
return False | |
#波半円が右回りか左回りかの決定 | |
wcobjects=[] #全波半円オブジェクトのリスト | |
wcMaxSize=0 #左半円オブジェクトの最大半径 | |
for object in objects: | |
if object.type==OBJ_WCIRCLE: | |
wcobjects.append(object) | |
rightList=[] #右半円のリスト | |
leftList=[] #左半円のリスト | |
if len(wcobjects)!=0: | |
rightList.append(wcobjects[0]) #最初のオブジェクトは右に配置 | |
wcobjects[0].rightRot=True | |
for i in range(1,len(wcobjects)): | |
leftColl=rightColl=0 #左と右の衝突数 | |
for elem in rightList: | |
if iscoll(wcobjects[i],elem): | |
rightColl+=1 | |
for elem in leftList: | |
if iscoll(wcobjects[i],elem): | |
leftColl+=1 | |
if rightColl<=leftColl: | |
print "right" | |
rightList.append(wcobjects[i]) | |
wcobjects[i].rightRot=True | |
else: | |
print "left" | |
leftList.append(wcobjects[i]) | |
wcobjects[i].rightRot=False | |
rad=abs(wcobjects[i].f.y-wcobjects[i].t.y)/2 | |
if rad > wcMaxSize: | |
wcMaxSize=rad | |
#左半円のぶんだけ全体を右にずらす | |
for object in objects: | |
object.translate(Pos(wcMaxSize,0)) | |
width+=wcMaxSize | |
return (height+frameHeight, width+frameWidth, objects) | |
def lower(aPos,bPos): | |
if aPos.y<bPos.y: | |
return aPos | |
else: | |
return bPos | |
def higher(aPos,bPos): | |
if aPos.y>bPos.y: | |
return aPos | |
else: | |
return bPos | |
import webbrowser | |
#画像の描画 | |
#直線と点と円と波線と矢印が描ける | |
#SVG形式(ベクタ画像)にする | |
import os | |
def drawGraphInSVG(height,width, objects, savefile=('','test','svg'),\ | |
browserView=False, fontDraw=True, arrowDraw=True, wavyLinePosAdj=True): | |
print "args=",height,width,objects,"AAAA",savefile,browserView,fontDraw,arrowDraw,wavyLinePosAdj | |
strokeWidth=1.5#2.5 | |
wavRatio=1.0 #0.5#波の横方向の大きさ。 | |
waveVertSize=5.0 #3.0#波の縦方向の大きさ | |
#waveHolSize=1.0 #波の横方向の大きさ。未実装 | |
waveStrokeRatio=0.9 #波線の線の太さ(の通常線に対する比) | |
fontSize=12 #フォントの大きさ | |
fontDist=(-20,-10) #各記号の元の点からの位置 | |
font="Verdana" #フォントの種類 | |
arrowSize=5 | |
arrowStrokeRatio=0.7 | |
#y=a sin(kx) where a=strokeWidth*2 b= waveRatio | |
xmlStr=[] | |
xmlStr.append('<?xml version="1.0" standalone="no"?>\n') | |
xmlStr.append('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" \n\ | |
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n') | |
xmlStr.append('<svg width="'+str(width)+'" height="'+str(height)+'"\n xmlns="http://www.w3.org/2000/svg" version="1.1">\n') | |
nowwc=0 #現在何番目の波線か(偶数番目の波線は左に回す) | |
#各オブジェクトを順番に描画する | |
#オブジェクトの形式 | |
for object in objects: | |
if object.type==OBJ_LINE: | |
#直線を描画 attr1=from attr2=to (from, toはタプル) | |
#draw.line((object[1],object[2]), fill=(0,0,0), width=10) | |
xmlStr.append('<line x1="'+str(object.f.x)+'" y1="'+str(object.f.y)+'"\ | |
x2="'+str(object.t.x)+'" y2="'+str(object.t.y)+'" stroke="black" stroke-width="'+str(strokeWidth)+'"/>\n') | |
if arrowDraw: | |
#矢印を描画 | |
#直線は縦方向であることを仮定 | |
theta=math.pi | |
P0=Pos(math.cos(theta+3*math.pi/2), -math.sin(theta+3*math.pi/2) )*arrowSize | |
P1=Pos(math.cos(theta+ math.pi/6), -math.sin(theta+ math.pi/6) )*arrowSize | |
P2=Pos(math.cos(theta+5*math.pi/6), -math.sin(theta+5*math.pi/6) )*arrowSize | |
mx,my=mean(object.f.x,object.t.x), mean(object.f.y,object.t.y) #中点 | |
xmlStr.append('<line x1="'+str(mx+P1.x)+'" y1="'+str(my++P1.y)+'"\ | |
x2="'+str(mx+P0.x)+'" y2="'+str(my++P0.y)+'" stroke="black" stroke-width="'+str(strokeWidth*arrowStrokeRatio)+'"/>\n') | |
xmlStr.append('<line x1="'+str(mx+P2.x)+'" y1="'+str(my++P2.y)+'"\ | |
x2="'+str(mx+P0.x)+'" y2="'+str(my++P0.y)+'" stroke="black" stroke-width="'+str(strokeWidth*arrowStrokeRatio)+'"/>\n') | |
elif object.type==OBJ_DLINE: | |
#破線を描画 attrは直線と同じ | |
pass | |
elif object.type==OBJ_WLINE or object.type==OBJ_WCIRCLE: #波線・波半円 | |
#WCIRCLEはメイン線上じゃないと問題が起こるかも | |
mode=object.type | |
#print object | |
#波線を描画 attrは直線と同じ | |
#最初に直線の中間点を導出 | |
Tx=math.pi/wavRatio | |
if mode==OBJ_WLINE: | |
startPos=object.f | |
endPos=object.t | |
length=math.sqrt( (object.t.x-object.f.x)**2 + (object.t.y-object.f.y)**2 ) | |
iPointNum=int(length/Tx) #中間点の数 | |
#print "iPointNum =",iPointNum | |
else: #OBJ_WCIRCLE | |
nowwc+=1 | |
if wavyLinePosAdj: | |
if object.rightRot: #右に回す | |
startPos=higher(object.f,object.t) | |
endPos=lower(object.f,object.t) | |
else: #左に回す | |
startPos=lower(object.f,object.t) | |
endPos=higher(object.f,object.t) | |
else: | |
startPos=object.f | |
endPos=object.t | |
length=math.sqrt( (endPos.x-startPos.x)**2 + (endPos.y-startPos.y)**2 )*math.pi/2 | |
iPointNum=int(length/Tx) #中間点の数 | |
#print "iPointNum =",iPointNum | |
iPoints=[] #中間点の導出。ただし中間点には始点も含む | |
center=Pos( (startPos.x+endPos.x)/2.0, (startPos.y+endPos.y)/2.0) | |
radius=(endPos.y-startPos.y)/2.0 | |
for i in xrange(iPointNum+1): | |
theta=math.pi*float(i)/iPointNum | |
x=center.x-radius*math.sin(theta) | |
y=center.y+radius*math.cos(theta) | |
iPoints.append( (x,y) ) | |
#各ベジェ曲線の作成 | |
(x1,y1)=0,0 #(x1,y1)-(x4,y4)は基準点 | |
(x2,y2)=math.pi/2-0.3,1.33*waveVertSize | |
(x3,y3)=math.pi/2+0.3,1.33*waveVertSize | |
(x4,y4)=math.pi,0 | |
#アフィン変換して各点を作成 | |
#arg=math.atan2(object[2][1]-object[1][1],object[2][0]-object[1][0]) #回転角 | |
#size=float(length)/iPointNum | |
#奇数の形(上側の波)はoが、偶数の形はeが最後についてる | |
if mode==OBJ_WLINE: | |
a=(endPos.x-startPos.x)/float(iPointNum)/math.pi | |
b=(endPos.y-startPos.y)/float(iPointNum)/math.pi | |
(x2do, y2do)=x2*a-y2*b,x2*b+y2*a | |
(x3do, y3do)=x3*a-y3*b,x3*b+y3*a | |
(x2de, y2de)=x2*a+y2*b,x2*b-y2*a | |
(x3de, y3de)=x3*a+y3*b,x3*b-y3*a | |
(x4,y4)=(endPos.x-startPos.x)/float(iPointNum),(endPos.y-startPos.y)/float(iPointNum) | |
xmlStr.append('<path\n') | |
xmlStr.append(' fill="none" fill-opacity="1" fill-rule="evenodd"\ | |
stroke="black" stroke-width="'+str(strokeWidth*waveStrokeRatio)+'"\n') | |
xmlStr.append('d=" M '+str(startPos.x)+','+str(startPos.y)+' \n') | |
#各点を作成 | |
for i in range(iPointNum): | |
if i%2==0: | |
xmlStr.append(' c '+str(x2do)+','+str(y2do)+' '+str(x3do)+','+str(y3do)+' '+str(x4)+','+str(y4)+' \n') | |
else: | |
xmlStr.append(' c '+str(x2de)+','+str(y2de)+' '+str(x3de)+','+str(y3de)+' '+str(x4)+','+str(y4)+' \n') | |
xmlStr.append('" />\n') | |
else: #OBJ_WCIRCLE | |
xmlStr.append('<path\n') | |
xmlStr.append(' fill="none" fill-opacity="1"\ | |
fill-rule="evenodd" stroke="black" stroke-width="'+str(strokeWidth*waveStrokeRatio)+'"\n') | |
xmlStr.append('d="\n') | |
for i in xrange(iPointNum): | |
#波線。注意すべきはこっちは相対座標じゃなくて絶対座標な点 | |
a=(iPoints[i+1][0]-iPoints[i][0])/math.pi | |
b=(iPoints[i+1][1]-iPoints[i][1])/math.pi | |
if i%2==0: | |
x2d,y2d=x2*a-y2*b+iPoints[i][0],x2*b+y2*a+iPoints[i][1] | |
x3d,y3d=x3*a-y3*b+iPoints[i][0],x3*b+y3*a+iPoints[i][1] | |
else: | |
x2d,y2d=x2*a+y2*b+iPoints[i][0],x2*b-y2*a+iPoints[i][1] | |
x3d,y3d=x3*a+y3*b+iPoints[i][0],x3*b-y3*a+iPoints[i][1] | |
x4d,y4d=iPoints[i+1][0],iPoints[i+1][1] | |
xmlStr.append('M '+str(iPoints[i][0])+','+str(iPoints[i][1])+' C '+str(x2d)+','+str(y2d)+' '+str(x3d)+','+str(y3d)+' '+str(x4d)+','+str(y4d)+' \n') | |
xmlStr.append('" />\n') | |
elif object.type==OBJ_CIRCLE: | |
#円を描画 attr1=center, attr2=radius | |
xmlStr.append('<circle cx="'+str(object.x.x)+'" cy="'+str(object.x.y)+'"\ | |
r="'+str(object.rad)+'" stroke="black" fill="none" fill-opacity="1" stroke-width="'+str(strokeWidth)+'"/>\n') | |
#rightArrow=(Pos(0,0),Pos(-arrowSize,-arrowSize),Pos(-arrowSize,+arrowSize)) | |
#leftArrow =(Pos(0,0),Pos( arrowSize,-arrowSize),Pos( arrowSize,+arrowSize)) | |
if arrowDraw: | |
#円上の矢印を描画 | |
args=object.args | |
Base=Pos(0,0) #矢印の見た目調整用 | |
#print "args=",args | |
if len(args)==1: #1点だけの円 | |
mPos=object.x+Pos(object.rad,0)#+Pos(math.cos(math.pi),-math.sin(math.pi))*object.rad | |
mPos+=Base | |
#print "mPos=",mPos | |
theta=0 | |
P0=Pos(math.cos(theta+3*math.pi/2), -math.sin(theta+3*math.pi/2) )*arrowSize | |
P1=Pos(math.cos(theta+ math.pi/6), -math.sin(theta+ math.pi/6) )*arrowSize | |
P2=Pos(math.cos(theta+5*math.pi/6), -math.sin(theta+5*math.pi/6) )*arrowSize | |
arrow=(mPos+P0, mPos+P1, mPos+P2 ) | |
#print arrow | |
xmlStr.append('<line x1="'+str(arrow[1].x)+'" y1="'+str(arrow[1].y)+'"\ | |
x2="'+str(arrow[0].x)+'" y2="'+str(arrow[0].y)+'" stroke="black" stroke-width="'+str(strokeWidth*arrowStrokeRatio)+'"/>\n') | |
xmlStr.append('<line x1="'+str(arrow[2].x)+'" y1="'+str(arrow[2].y)+'"\ | |
x2="'+str(arrow[0].x)+'" y2="'+str(arrow[0].y)+'" stroke="black" stroke-width="'+str(strokeWidth*arrowStrokeRatio)+'"/>\n') | |
else: #2点以上の円。右回り。 | |
for i in range(len(args)): | |
arg=args[i] | |
if i==0: | |
argb=args[-1] | |
else: | |
argb=args[i-1] | |
if arg>argb: | |
theta=mean(arg,argb)-math.pi | |
else: | |
theta=mean(arg,argb) | |
P0=Pos(math.cos(theta+3*math.pi/2), -math.sin(theta+3*math.pi/2) )*arrowSize | |
P1=Pos(math.cos(theta+ math.pi/6), -math.sin(theta+ math.pi/6) )*arrowSize | |
P2=Pos(math.cos(theta+5*math.pi/6), -math.sin(theta+5*math.pi/6) )*arrowSize | |
arrow=(Base+P0, Base+P1, Base+P2) | |
mPos=object.x+Pos(math.cos(theta),-math.sin(theta))*object.rad | |
arrow=(arrow[0]+mPos, arrow[1]+mPos, arrow[2]+mPos) | |
xmlStr.append('<line x1="'+str(arrow[1].x)+'" y1="'+str(arrow[1].y)+'"\ | |
x2="'+str(arrow[0].x)+'" y2="'+str(arrow[0].y)+'" stroke="black" stroke-width="'+str(strokeWidth*arrowStrokeRatio)+'"/>\n') | |
xmlStr.append('<line x1="'+str(arrow[2].x)+'" y1="'+str(arrow[2].y)+'"\ | |
x2="'+str(arrow[0].x)+'" y2="'+str(arrow[0].y)+'" stroke="black" stroke-width="'+str(strokeWidth*arrowStrokeRatio)+'"/>\n') | |
elif object.type==OBJ_POINT: | |
#点を描画 attr1=point | |
xmlStr.append('<circle cx="'+str(object.x.x)+'" cy="'+str(object.x.y)+'"\ | |
r="'+str(strokeWidth*1.5)+'" fill="black" stroke="black" stroke-width="'+str(strokeWidth)+'"/>\n') | |
#文字を描画 attr2=その場所の記号 | |
if fontDraw: | |
pointName=object.symbol.replace("d","'") | |
xmlStr.append('<text x="'+str(object.x.x+fontDist[0])+'" y="'+str(object.x.y+fontDist[1])+'"\ | |
fill="black" font-family="'+font+'" font-size="'+str(fontSize)+'" >'+pointName+'</text>\n') | |
else: | |
print "unexpected object!",object | |
#return | |
#img.show() #PNGファイルで保存 | |
#img.save(savefile, 'PNG', dpi=(72,72)) #PNGファイルで保存 | |
#del draw | |
xmlStr.append("</svg>") | |
filename=os.path.join( os.curdir, savefile[0], (savefile[1]+"."+savefile[2]) ) | |
#ディレクトリが存在するかどうかのチェック(存在しなかったら作る) | |
if savefile[0]!="" and not savefile[0] in os.listdir(os.curdir): | |
print "create directory",savefile[0] | |
os.mkdir( os.path.join(os.curdir,savefile[0]) ) | |
print "save to "+filename | |
fileobj=file(filename,"w") | |
fileobj.writelines(xmlStr) | |
fileobj.close() | |
if browserView: | |
webbrowser.open(filename) | |
#ファインマンダイアグラム計算 | |
# | |
#データ構造 | |
#再帰するメイン部分 | |
#便利のため | |
STR=0 | |
WAV=1 | |
import copy; | |
def getDiagramr(allNodes, unusedNodes, lines, unusedContainers): | |
rets=[] #戻り値 | |
#print "func_getDiagramr called",unusedNodes,lines,unusedContainers | |
if len(unusedNodes)==0: | |
if len(unusedContainers)==0: | |
#終了 | |
return [lines,] | |
else: | |
#コンテナが残っているのにノードを使い切った場合 | |
#非連結グラフになってしまう | |
#print "disconnected graph!",lines | |
return [] | |
#一本線引いて再帰。線を引きうる場所が2箇所以上ある場合は分岐。 | |
if allNodes[0]=="xt": | |
#ありえない頂点の残り方 | |
print 'unexpected state : only "xt" node left' | |
else: | |
if isStart(unusedNodes[0]): | |
#使われてない最初の点が線の始点に | |
lineStart=unusedNodes[0] | |
unusedNodes=unusedNodes[1:] #始点削除 | |
#終点候補を探る | |
for elem in unusedNodes: | |
if isEnd(elem): #終点なら | |
#再帰 | |
newLines=copy.deepcopy(lines) | |
#線追加 | |
newLines.append((lineStart, elem)) | |
#unusedNodesから終点削除 | |
newUnusedNodes=copy.deepcopy(unusedNodes) | |
newUnusedNodes.remove(elem) | |
#newUnusedContainers=copy.deepcopy(unusedContainers) #これ要らないかも | |
rets+=getDiagramr(allNodes, newUnusedNodes, newLines, unusedContainers) #再帰 | |
if len(unusedContainers)!=0: | |
#新しいコンテナを開ける | |
#ノードリストでxtを最後にしておくことに注意 | |
newLines=copy.deepcopy(lines) | |
newLines.append( (lineStart,"xt"+str(unusedContainers[0])) ) | |
newUnusedNodes=copy.deepcopy(unusedNodes) | |
newUnusedNodes=newUnusedNodes[:-1]+createBlockf(unusedContainers[0])+[newUnusedNodes[-1],] | |
newUnusedContainers=copy.deepcopy(unusedContainers) | |
newUnusedContainers=newUnusedContainers[1:] | |
#print "open new container",unusedContainers[0] | |
rets+=getDiagramr(allNodes, newUnusedNodes, newLines, newUnusedContainers) #再帰 | |
else: | |
#使われてない最初の点が線の終点に | |
lineEnd=unusedNodes[0] | |
unusedNodes=unusedNodes[1:] #終点削除 | |
#終点候補を探る | |
for elem in unusedNodes: | |
if isStart(elem): #始点なら | |
#再帰する | |
newLines=copy.deepcopy(lines) | |
#線追加 | |
newLines.append((elem, lineEnd)) | |
#unusedNodesから始点削除 | |
newUnusedNodes=copy.deepcopy(unusedNodes) | |
newUnusedNodes.remove(elem) | |
#newUnusedContainers=copy.deepcopy(unusedContainers) #これ要らないかも | |
rets+=getDiagramr(allNodes, newUnusedNodes, newLines, unusedContainers) #再帰 | |
if len(unusedContainers)!=0: | |
#新しいコンテナを開ける | |
#ノードリストでxtを最後にしておくことに注意 | |
newLines=copy.deepcopy(lines) | |
newLines.append( ("xf"+str(unusedContainers[0]), lineEnd)) | |
newUnusedNodes=copy.deepcopy(unusedNodes) | |
newUnusedNodes=newUnusedNodes[:-1]+createBlockt(unusedContainers[0])+[newUnusedNodes[-1],] | |
newUnusedContainers=copy.deepcopy(unusedContainers) | |
newUnusedContainers=newUnusedContainers[1:] | |
#print "open new container",unusedContainers[0] | |
rets+=getDiagramr(allNodes, newUnusedNodes, newLines, newUnusedContainers) #再帰 | |
#print "func_getDiagramr end",unusedNodes,lines,unusedContainers | |
return rets | |
def getDiagram(size, browser=False, texOutPut=False,\ | |
fontDraw=True, arrowDraw=True, wavyLinePosAdj=True, saveDir=""): | |
allNodes=[] | |
allNodes.append("yf") | |
for i in range(1,size): | |
#ブロック追加 | |
allNodes+=createBlock(i) | |
allNodes.append("xt") | |
#未使用ノード集には順番が重要 | |
#一点も使われていないブロックはunusedCotainersに格納されている | |
unusedNodes=["yf","xt"] | |
#直線 | |
StrLines=[] | |
#波線 | |
waveLines=[] | |
lines=[] | |
#使われていないコンテナ(xfN, xtN, xfdN, xtdNのブロックのリスト) | |
unusedContainers=range(1,size+1) | |
diagrams=getDiagramr(allNodes, unusedNodes, lines, unusedContainers) | |
if texOutPut: #texの数式で出力モード | |
filename="test"+str(size)+".tex" | |
#print "outPut :",filename | |
fileobj=file(filename, "w") | |
fileobj.write( r"""\documentclass{jsarticle} | |
\begin{document}""") | |
for lineAndLoops in diagrams: | |
#print lineAndLoops | |
texLines="" | |
for aline in lineAndLoops: | |
texLines+=toLatex(aline)+" " | |
fileobj.write(r"\[") | |
fileobj.write(texLines) | |
fileobj.write("\\]\n") | |
#print "mainline and loops :", decompose(allNodes, lines) | |
fileobj.write("\\end{document}\n") | |
return | |
i=0 | |
for lineAndLoops in diagrams: | |
i+=1 | |
print "line and loops",lineAndLoops | |
decon=decompose(allNodes, lineAndLoops) | |
#print decon | |
rets=place(decon) | |
#print rets | |
if rets: | |
drawGraphInSVG(rets[0],rets[1],rets[2], (saveDir,"test"+str(i), "svg"), browserView=browser, fontDraw=fontDraw , arrowDraw=arrowDraw, wavyLinePosAdj=wavyLinePosAdj) | |
else: | |
print "unimplemented",lineAndLoops | |
def getBigDiagram(size, vertical=True, browser=False,\ | |
fontDraw=True, arrowDraw=True, wavyLinePosAdj=True, saveDir=""): | |
#<<ダイアグラム作成、ただし一つの巨大なsvgファイルに>>みたいなっ! | |
#縦の長さは確定しているので、とりあえず横長のsvg画像を作成 | |
allNodes=[] | |
allNodes.append("yf") | |
for i in range(1,size): | |
#ブロック追加 | |
allNodes+=createBlock(i) | |
allNodes.append("xt") | |
#未使用ノード集には順番が重要 | |
#一点も使われていないブロックはunusedCotainersに格納されている | |
unusedNodes=["yf","xt"] | |
#直線 | |
StrLines=[] | |
#波線 | |
waveLines=[] | |
lines=[] | |
#使われていないコンテナ(xfN, xtN, xfdN, xtdNのブロックのリスト) | |
unusedContainers=range(1,size+1) | |
# print r"""\documentclass{jsarticle} | |
#\begin{document}""" | |
diagrams=getDiagramr(allNodes, unusedNodes, lines, unusedContainers) | |
i=0 | |
#graphics=[] #placeの戻り値のリスト | |
newObjects=[] | |
#画像を順番にずらす | |
if vertical: | |
height=0 | |
widthMax=0 | |
else: | |
height=0 #horizontal 複数行表示 | |
holizontalNum=5 | |
width=0 | |
widthMax=0 | |
nowHolNum=0 | |
for lineAndLoops in diagrams: | |
i+=1 | |
print "line and loops",lineAndLoops | |
decon=decompose(allNodes, lineAndLoops) | |
#print decon | |
agraph=place(decon) | |
#def place :return (height+frameHeight, width+frameWidth, objects) | |
#placeの戻り値はsvg画像に(ほぼ)一対一対応している | |
if agraph[1] > widthMax: | |
widthMax=agraph[1] | |
else: #horizontal | |
if nowHolNum==holizontalNum: | |
nowHolNum=0 | |
height+=HEIGHT_DEF+FRAMEHEIGHT_DEF | |
width=0 | |
for object in agraph[2]: | |
#print "object=",object | |
if vertical: | |
object.translate( Pos(0,height) ) | |
else: | |
object.translate( Pos(width,height) ) | |
#print "object'=",object | |
newObjects.append(copy.copy(object) ) | |
if vertical: | |
height+=agraph[0] | |
else: #horizontal | |
width+=agraph[1] | |
if width > widthMax: | |
widthMax=width | |
nowHolNum+=1 | |
#print "newObjects =",newObjects | |
if vertical: | |
drawGraphInSVG(height, widthMax, newObjects, (saveDir,"testBig"+str(size), "svg"), browserView=browser, \ | |
fontDraw=fontDraw , arrowDraw=arrowDraw, wavyLinePosAdj=wavyLinePosAdj) | |
else: #horizontal | |
drawGraphInSVG(height+ALLHEIGHT_DEF, widthMax, newObjects, (saveDir,"testBig"+str(size), "svg"), \ | |
browserView=browser , fontDraw=fontDraw , arrowDraw=arrowDraw, wavyLinePosAdj=wavyLinePosAdj) | |
def writeHtml(n): | |
f=file("display.html", "w") | |
astr='' | |
astr="<h1>There are "+str(n)+" diagrams.</h1>" | |
for i in range(1,n+1): | |
astr += '<h2>diagram '+str(i)+'</h2>' | |
astr += '<object data="test'+str(i)+'.svg" type="image/svg+xml">diagram'+str(i)+'</object><br>' | |
f.write(astr) | |
if __name__=='__main__': | |
import sys | |
from optparse import OptionParser #コマンドライン解析の標準ライブラリ | |
usage = """ | |
Usage: %prog [options] arg\n\n | |
Calculate and Draw all One-particle Feynman Diagrams of degree s (s is determined by option -s). | |
Outputs are SVG files(SVG is vector graphics format). | |
Term Nums of Feynman Diagrams: | |
degree 1 - 2 terms | |
degree 2 - 10 terms | |
degree 3 - 74 terms | |
degree 4 - 706 terms | |
degree 5 - 8162 terms | |
degree 6 - 110410 terms | |
-s(size option) more than 5 takes much time!!! | |
For questions , requests and bugs , report to elbreth<elb.phys@gmail.com>""" | |
parser = OptionParser(usage) | |
parser.add_option("-s" , "--size" , type="int", dest="size", \ | |
default=1, help="size(degree) of diagram to calculate. default is 1") | |
parser.add_option("-f" , "--folder", "--directory" , type="string", dest="saveDir", \ | |
default="", help='specify directory to save files. for example, "-f test" will save files to "./test/"') | |
parser.add_option("-d" , "--disp", action="store_true", dest="browser", \ | |
default=False, help="redirect to browser.") | |
parser.add_option("-t" , "--tex", action="store_true", dest="texout", \ | |
default=False, help="output in tex file (for development)") | |
parser.add_option("-b" , "--big" , action="store_true", dest="is_big", \ | |
default=False, help="output is integrated into one big file") | |
parser.add_option("--bh" , "--bighorizontal", action="store_true", dest="is_big_vertical", \ | |
default=False) | |
parser.add_option("-p" , "--psyco", action="store_true", dest="usepsyco", \ | |
help="use psyco to boost program speed") | |
parser.add_option("--np" , "--nopsyco", action="store_false", dest="usepsyco", \ | |
default=False, help="don't use psyco. for enviroment without psyco (default)") | |
parser.add_option("--nf" , "--noFont", action="store_false", dest="usefont", \ | |
default=True, help="don't draw font") | |
parser.add_option("--na" , "--noArrow", action="store_false", dest="usearrow", \ | |
default=True, help="don't draw arrow") | |
parser.add_option("--nwa" , "--noWavLinePosAdj", action="store_false", dest="usewlpa", \ | |
default=True, help="don't adjust position of wavy line (for development)") | |
parser.add_option("--nl" , "--noLimit", "--noSizeLimit", action="store_false", dest="isLimit", \ | |
default=True, help="unlimit the size limit") | |
(options, args) = parser.parse_args() | |
size=options.size | |
if options.isLimit: | |
if options.browser: | |
if size>2: | |
print "size too big (you will open more than 50 windows!!).\ | |
\nrun with smaller size, or use option --nl to lift this limit." | |
sys.exit() | |
else: | |
if size>4: | |
print "size too big (it may take too much time).\ | |
\nrun with smaller size, or use option --nl to lift this limit." | |
sys.exit() | |
if options.usepsyco: | |
print "using psyco" | |
import psyco | |
psyco.full() | |
if options.is_big: | |
getBigDiagram( size, browser=options.browser, fontDraw=options.usefont, \ | |
arrowDraw=options.usearrow, wavyLinePosAdj=options.usewlpa, saveDir=saveDir) | |
elif options.is_big_vertical: | |
getBigDiagram( size, vertical=False, browser=options.browser , fontDraw=options.usefont, \ | |
arrowDraw=options.usearrow, wavyLinePosAdj=options.usewlpa, saveDir=options.saveDir) | |
else: | |
getDiagram( size, browser=options.browser ,texOutPut=options.texout , fontDraw=options.usefont, \ | |
arrowDraw=options.usearrow, wavyLinePosAdj=options.usewlpa, saveDir=options.saveDir) | |
termNum={1:2, 2:10, 3:74, 4:706, 5:8162, 6:110410} | |
writeHtml(termNum[size]) |
FeynmanDiagramというレポジトリを作った
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
ファインマンダイアグラム描画プログラム。コードはあまり綺麗ではないです。
example
python feynman.py -s 3