//================= Canvas elements let staticLayer = document.getElementById('static'); let beamLineLayer = document.getElementById('beamLine'); const deg = Math.PI/180; function rotateACW(xy, center, rad){ let haha = [xy[0]-center[0], xy[1]-center[1]]; let kaka = [ haha[0]*Math.cos(rad) - haha[1]*Math.sin(rad), haha[0]*Math.sin(rad) + haha[1]*Math.cos(rad)]; return [ kaka[0] + center[0], kaka[1] + center[1]]; } function translate(xy, t){ return [xy[0] + t[0], xy[1] + t[1]]; } function distance(xy1, xy2){ return Math.sqrt( Math.pow(xy1[0]-xy2[0],2) + Math.pow(xy1[1]-xy2[1],2)); } let colors = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]; let color = { BeamPipe : ['red', 'grey'], Dipole : ['gold', '#CDCD5B'], Deflector : ['Orange', '#228522'], Qpole : ['#7F7FFF', '#8F8FBC'], Detector : ['Yellow', '#8B8B0A'], LINAC : ['Cyan', '#44AAAA'], Tandem : [ '#782F40', '#CEB888'], Buncher : ['Ivory', '#DD33FF'], SNICS : ['tan', 'tan4'], RFsourcce : ['Olivedrab', 'Olivedrab4'], Other : ['Black', 'Red'] } class basicShape{ constructor(layer, color){ this.layer = layer; this.shape = new Path2D(); this.entracePos = [0,0]; this.exitPos = [0,0]; this.rad = 0; this.color = color; } GetExitPos(d){ let l = [ d * Math.sin(this.rad), - d * Math.cos(this.rad)]; return translate(this.exitPos, l); } clear(){ let ctx = this.layer.getContext('2d'); ctx.save(); ctx.globalCompositeOperation = 'destination-out'; ctx.fill(this.shape); ctx.stroke(this.shape); ctx.restore(); } draw(onOff){ let ctx = this.layer.getContext('2d'); if( onOff ){ ctx.fillStyle = this.color[0]; }else{ ctx.fillStyle = this.color[1]; } ctx.fill(this.shape); } } class tandemClass extends basicShape{ constructor(xy, l, w, color){ super(staticLayer, color); this.exitPos = [ xy[0], xy[1] - w - l]; this.shape.rect(xy[0] - w/2, xy[1] - l - w/2, w, l); this.shape.arc(xy[0], xy[1]-w/2, w/2, 0, Math.PI); this.shape.arc(xy[0], xy[1]-w/2 - l, w/2, Math.PI, 2* Math.PI); } } class beamLine extends basicShape{ constructor(xy, rad, l){ super(beamLineLayer, color.BeamPipe); this.offset = 0; this.lineWidth = 10; this.exitPos = [xy[0], xy[1] - l]; this.exitPos = rotateACW(this.exitPos, xy, rad); this.shape.moveTo(xy[0], xy[1]); this.shape.lineTo(this.exitPos[0], this.exitPos[1]); } draw(isDashed){ this.clear(); let ctx = this.layer.getContext('2d'); if(isDashed){ ctx.setLineDash([10,6]); ctx.lineDashOffset = -this.offset; ctx.strokeStyle = this.color[0]; }else{ ctx.strokeStyle = this.color[1]; ctx.setLineDash([]); } ctx.lineWidth = 10; ctx.stroke(this.shape); } march(){ this.offset++; if( this.offset > 16) this.offset = 0; this.draw(true); //setTimeout(this.march.bind(this), 20); } } class beamRectElement extends basicShape{ constructor(xy, rad, l, w, color){ super(staticLayer, color); let A = [xy[0]-w/2, xy[1]]; let B = [xy[0]+w/2, xy[1]]; let C = [xy[0]+w/2, xy[1] - l]; let D = [xy[0]-w/2, xy[1] - l]; A = rotateACW(A, xy, rad); B = rotateACW(B, xy, rad); C = rotateACW(C, xy, rad); D = rotateACW(D, xy, rad); this.shape.moveTo(A[0], A[1]); this.shape.lineTo(B[0], B[1]); this.shape.lineTo(C[0], C[1]); this.shape.lineTo(D[0], D[1]); this.shape.closePath(); this.rad = rad; this.exitPos = [xy[0], xy[1] - l]; this.exitPos = rotateACW(this.exitPos, xy, rad); } } class beamCircleElement extends basicShape{ constructor(xy, r, rad0, rad1, color){ super(staticLayer, color); this.shape.moveTo(xy[0], xy[1]); this.shape.arc(xy[0], xy[1], r, rad0, rad1); let rad = (rad0 + rad1)/2; let l = [r*Math.cos(rad), r*Math.sin(rad)]; this.exitPos = [xy[0] + l[0], xy[1] + l[1]]; // the middle of the arc } GetExitPos(frac){ let rad = rad0 + Math.abs(rad0 - rad1) * frac; let l = [r*Math.cos(rad), r*Math.sin(rad)]; return [xy[0] + l[0], xy[1] + l[1]]; } } class beamSpliter extends basicShape{ constructor(xy, r, rad, color){ super(staticLayer, color); this.entracePos = xy; this.r = r; let w = r; let l = r/2; let A = [xy[0]+w/2, xy[1] - l]; let B = [xy[0]+w/2, xy[1]]; let C = [xy[0]-w/2, xy[1]]; let D = [xy[0]-w/2, xy[1] - l]; A = rotateACW(A, xy, rad); B = rotateACW(B, xy, rad); C = rotateACW(C, xy, rad); D = rotateACW(D, xy, rad); this.shape.moveTo(A[0], A[1]); this.shape.lineTo(B[0], B[1]); this.shape.lineTo(C[0], C[1]); this.shape.lineTo(D[0], D[1]); this.rad = rad; this.rad0 = rad - Math.PI*3/4; this.rad1 = rad - Math.PI/4; this.shape.arc(xy[0], xy[1], r, this.rad0 , this.rad1); } GetExitPos(frac, d){ let rad = this.rad0 + Math.abs(this.rad0 - this.rad1) * frac; this.exitAng = rad + 90 * deg; let l = [(this.r + d)*Math.cos(rad), (this.r + d)*Math.sin(rad)]; return translate(this.entracePos, l); } GetExitAng(frac){ let rad = this.rad0 + Math.abs(this.rad0 - this.rad1) * frac; this.exitAng = rad + 90 * deg; return this.exitAng; } } class beamDipole extends basicShape{ constructor(xy, r, rad, ang, color){ super(staticLayer, color); this.rad = rad; this.entracePos = xy; let A = [xy[0] + r/2, xy[1]]; let B = [A[0] , A[1] - r*3/2*Math.tan(rad/2)]; let C = [xy[0] - r - r*3/2 * Math.cos(rad), xy[1] - r*3/2 * Math.sin(rad)]; let D = [xy[0] - r - r/2 * Math.cos(rad), xy[1] - r/2 * Math.sin(rad)]; let F = [xy[0] - r/2, xy[1]]; let E = [xy[0] - r/2, xy[1] - r/2*Math.tan(rad/2)]; A = rotateACW(A, xy, ang); B = rotateACW(B, xy, ang); C = rotateACW(C, xy, ang); D = rotateACW(D, xy, ang); E = rotateACW(E, xy, ang); F = rotateACW(F, xy, ang); this.shape.moveTo(A[0], A[1]); this.shape.arcTo(B[0], B[1], C[0], C[1], r*3/2); this.shape.lineTo(D[0],D[1]); this.shape.arcTo(E[0], E[1], F[0], F[1], r/2); this.shape.lineTo(A[0], A[1]); this.exitPos = [(C[0] + D[0])/2, (C[1] + D[1])/2]; } GetExitPos(d){ let haha = [ - d * Math.sin(this.rad), - d * Math.cos(this.rad)]; return translate(this.exitPos, haha); } } ///========================= Floor plan let windowSize = [3840, 2160]; // 4K let sourceLine; { let RFSource1a = new beamRectElement([windowSize[0]*0.9, windowSize[1]*0.8], 0, 40, 100, color.RFsourcce); let RFSource1b = new beamRectElement(RFSource1a.exitPos, 0, 40, 20, color.RFsourcce); let s0 = new beamSpliter(RFSource1b.GetExitPos(120), 50, Math.PI, color.Dipole); let b0a = new beamLine(RFSource1b.exitPos, 0, 200); let tandem = new tandemClass(b0a.exitPos, 100, 100, color.Tandem); let b0b = new beamLine(tandem.exitPos, 0, 300); b0b.offset = 8; let q0 = new beamRectElement(tandem.GetExitPos(50), 0, 60, 60, color.Qpole); let df0a = new beamRectElement(q0.GetExitPos(50), 0, 30, 40, color.Deflector); let df0b = new beamRectElement(df0a.GetExitPos(20), 0, 30, 40, color.Deflector); sourceLine = {RFSource1a, RFSource1b, b0a, s0, tandem, b0b, q0, df0a, df0b}; } //============ beam line for target room 1 let targetRoom1; { let dipole = new beamDipole(sourceLine.b0b.exitPos, 80, Math.PI/2, 0, color.Dipole); let beampipe = new beamLine(dipole.exitPos, -Math.PI/2, 200, color.BeamPipe); let fan = new beamSpliter(beampipe.exitPos, 50, -100 * deg, color.Deflector); let upperLine; { //---------- upper beam line let b1a_0 = new beamLine(fan.GetExitPos(0.8, 0), fan.exitAng , 400); b1a_0.offset = 8; let q1a = new beamRectElement(fan.GetExitPos(0.8, 100), fan.exitAng, 60, 60, color.Qpole); let df1a = new beamRectElement(q1a.GetExitPos(30), fan.exitAng, 30, 40, color.Dipole); let b1a_1 = new beamLine(b1a_0.exitPos, fan.exitAng, 300); let GammaStation = new beamCircleElement(b1a_0.exitPos, 100, 0, Math.PI*2, color.Detector); let Catrina = new beamCircleElement(b1a_1.exitPos, 100, 0, Math.PI*2, color.Detector); upperLine = {b1a_0, q1a, df1a, b1a_1, GammaStation, Catrina}; } //----------- middle beam line let middleLine; { let b1b = new beamLine(fan.GetExitPos(0.55, 0), fan.GetExitAng(0.55) , 300); b1b.offset = 8; middleLine = {b1b}; } //----------- lower beam line let lowerLine; { let b1c = new beamLine(fan.GetExitPos(0.35, 0), fan.GetExitAng(0.35) , 300); let q1c = new beamRectElement( fan.GetExitPos(0.35, 100), fan.GetExitAng(0.35), 60, 60, color.Qpole); let df1c = new beamRectElement( q1c.GetExitPos(50), fan.GetExitAng(0.35), 30, 40, color.Deflector); lowerLine = {b1c, q1c, df1c}; } targetRoom1 = {dipole, beampipe, fan, upperLine, middleLine, lowerLine}; } //================= beam line to target room 2 let targetRoom2; { let b2 = new beamLine(sourceLine.b0b.exitPos, 0, 600); b2.offset = 11; let q2 = new beamRectElement( sourceLine.b0b.GetExitPos(150), 0, 60, 60, color.Qpole); let df2 = new beamRectElement( q2.GetExitPos(50), 0, 40, 40, color.Deflector); let q3 = new beamRectElement( df2.GetExitPos(50), 0, 60, 60, color.Qpole); let d2 = new beamDipole(b2.GetExitPos(0), 80, 90 * deg, 0, color.Dipole); let b3 = new beamLine(d2.exitPos, -90 * deg, 1700, color.BeamPipe); let df3 = new beamRectElement(d2.GetExitPos(100), -90 * deg, 40, 40, color.Deflector); let q4 = new beamRectElement( df3.GetExitPos(50), -90 * deg, 60, 60, color.Qpole); let df4 = new beamRectElement(q4.GetExitPos(50), -90 * deg, 40, 40, color.Deflector); let buncher = new beamCircleElement(df4.GetExitPos(100), 50, 0 , Math.PI*2, color.Buncher); let linac1 = new beamRectElement(d2.GetExitPos(600), -90 * deg, 200, 80, color.LINAC); let linac2 = new beamRectElement(linac1.GetExitPos(30), -90 * deg, 200, 80, color.LINAC); let linac3 = new beamRectElement(linac2.GetExitPos(30), -90 * deg, 200, 80, color.LINAC); let df5 = new beamRectElement(linac3.GetExitPos(50), -90 * deg, 40, 40, color.Deflector); let df6 = new beamRectElement(df5.GetExitPos(50), -90 * deg, 40, 40, color.Deflector); let q5 = new beamRectElement( df6.GetExitPos(50), -90 * deg, 60, 60, color.Qpole); let df7 = new beamRectElement(q5.GetExitPos(50), -90 * deg, 40, 40, color.Deflector); let fan2 = new beamSpliter(b3.exitPos, 100, -100 * deg, color.Dipole); let ResolutLine; { let frac = 0.7; let b2a = new beamLine(fan2.GetExitPos(frac, 0), fan2.GetExitAng(frac), 500); let df2a_0 = new beamRectElement( fan2.GetExitPos(frac, 100), fan2.GetExitAng(frac), 30, 40, color.Deflector); let q2a = new beamRectElement(df2a_0.GetExitPos(30), fan2.GetExitAng(frac), 60, 60, color.Qpole); let df2a_1 = new beamRectElement( q2a.GetExitPos(30), fan2.GetExitAng(frac), 30, 40, color.Deflector); let df2a_2 = new beamRectElement( df2a_1.GetExitPos(30), fan2.GetExitAng(frac), 30, 40, color.Deflector); let d3 = new beamDipole(b2a.GetExitPos(0), 80, 90* deg, -40 * deg, color.Dipole); let b2a_1 = new beamLine( d3.GetExitPos(0), -95 * deg, 500); let Resolut = new beamCircleElement(b2a_1.GetExitPos(0), 100, 0, Math.PI*2, color.Detector); ResolutLine = {b2a, df2a_0, q2a, df2a_1, df2a_2, d3, b2a_1, Resolut}; } let AnasenLine; { let frac = 0.5; let b2b = new beamLine(fan2.GetExitPos(frac, 0), fan2.GetExitAng(frac), 500); let q2b = new beamRectElement(fan2.GetExitPos(frac, 30), fan2.GetExitAng(frac), 60, 60, color.Qpole); let df2b = new beamRectElement( fan2.GetExitPos(frac, 120), fan2.GetExitAng(frac), 30, 40, color.Deflector); let Anasen = new beamCircleElement(b2b.GetExitPos(0), 100, 0, Math.PI*2, color.Detector); AnasenLine = {b2b, q2b, df2b, Anasen}; } let lowerLine; { let frac = 0.3; let b2c = new beamLine(fan2.GetExitPos(frac, 0), fan2.GetExitAng(frac), 500); let q2c = new beamRectElement(fan2.GetExitPos(frac, 100), fan2.GetExitAng(frac), 60, 60, color.Qpole); let df2c = new beamRectElement( fan2.GetExitPos(frac, 200), fan2.GetExitAng(frac), 30, 40, color.Deflector); let fan2c = new beamSpliter(b2c.exitPos, 80, -130 * deg, color.Dipole); let SplitPoleLine; { let frac = 0.7; let b2c_1 = new beamLine(fan2c.GetExitPos(frac, 0), fan2c.GetExitAng(frac), 500); let q2c_1 = new beamRectElement(fan2c.GetExitPos(frac, 100), fan2c.GetExitAng(frac), 60, 60, color.Qpole); let df2c_1a = new beamRectElement( q2c_1.GetExitPos(30), fan2c.GetExitAng(frac), 30, 40, color.Deflector); let df2c_1b = new beamRectElement( df2c_1a.GetExitPos(30), fan2c.GetExitAng(frac), 30, 40, color.Deflector); let SPS = new beamCircleElement(b2c_1.GetExitPos(0), 100, 0, Math.PI*2, color.Detector); SplitPoleLine = {b2c_1, q2c_1, df2c_1a, df2c_1b, SPS}; } let ClarionLine; { let frac = 0.4; let b2c_2 = new beamLine(fan2c.GetExitPos(frac, 0), fan2c.GetExitAng(frac), 500); let q2c_2 = new beamRectElement(fan2c.GetExitPos(frac, 100), fan2c.GetExitAng(frac), 60, 60, color.Qpole); let df2c_2a = new beamRectElement( q2c_2.GetExitPos(30), fan2c.GetExitAng(frac), 30, 40, color.Deflector); let df2c_2b = new beamRectElement( df2c_2a.GetExitPos(30), fan2c.GetExitAng(frac), 30, 40, color.Deflector); let Clarion2 = new beamCircleElement(b2c_2.GetExitPos(0), 100, 0, Math.PI*2, color.Detector); ClarionLine = {b2c_2, q2c_2, df2c_2a, df2c_2b, Clarion2}; } lowerLine = {b2c, q2c, df2c, fan2c, SplitPoleLine, ClarionLine}; } targetRoom2 = {b2, q2, df2, q3, d2, b3, df3, q4, df4, buncher, linac1, linac2, linac3, df5, df6, q5, df7, fan2, ResolutLine, AnasenLine, lowerLine}; } for( const ele in sourceLine){ sourceLine[ele].draw(true); } targetRoom1.dipole.draw(true); targetRoom1.beampipe.draw(true); targetRoom1.fan.draw(true); targetRoom1.upperLine.b1a_0.draw(true); targetRoom1.upperLine.q1a.draw(true); targetRoom1.upperLine.df1a.draw(true); targetRoom1.upperLine.b1a_1.draw(false); targetRoom1.upperLine.GammaStation.draw(true); targetRoom1.upperLine.Catrina.draw(false); targetRoom1.middleLine.b1b.draw( false); targetRoom1.lowerLine.b1c.draw( false); targetRoom1.lowerLine.q1c.draw(false); targetRoom1.lowerLine.df1c.draw(false); for( const ele in targetRoom2){ try{ targetRoom2[ele].draw(false); }catch(err){ for( const haha in targetRoom2[ele]){ try{ targetRoom2[ele][haha].draw(false); }catch(err){ for( const kaka in targetRoom2[ele][haha]){ targetRoom2[ele][haha][kaka].draw(false); } } } } } function lineMotion(){ sourceLine.b0a.march(); sourceLine.b0b.march(); targetRoom1.beampipe.march(); targetRoom1.upperLine.b1a_0.march(); setTimeout(lineMotion, 20); } lineMotion();