//================= 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 = { //[on, off] BeamPipe : ['red', 'grey'], Dipole : ['gold', '#DEDE6C'], Deflector : ['Orange', '#228522'], Qpole : ['#4E4EEE', '#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,8]); 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+=1; if( this.offset > 18) this.offset = 0; this.draw(true); //setTimeout(this.march.bind(this), 20); } } class multiBeamLine extends basicShape{ constructor(posArray){ super(beamLineLayer, color.BeamPipe); this.posArray = posArray; this.lineWidth = 10; this.offset = 0; this.shape.moveTo(this.posArray[0][0], this.posArray[0][1]); for( let i = 1; i < posArray.length; i++) { this.shape.lineTo(this.posArray[i][0], this.posArray[i][1]); } } draw(isDashed){ this.clear(); let ctx = this.layer.getContext('2d'); if(isDashed){ ctx.setLineDash([8,8]); 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+=2; if( this.offset > 16) this.offset = 0; this.draw(true); //setTimeout(this.march.bind(this), 20); } clear(){ let ctx = this.layer.getContext('2d'); ctx.save(); ctx.globalCompositeOperation = 'destination-out'; ctx.stroke(this.shape); ctx.restore(); } } 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 detectorStation extends beamCircleElement { constructor(xy, name){ super(xy, 100, 0, Math.PI*2, color.Detector); this.xy = xy; this.name = name; this.entracePos = xy; } draw(onoff){ super.draw(onoff); let ctx = staticLayer.getContext("2d"); ctx.font = "40px Verdana"; ctx.fillStyle = 'black'; let text = ctx.measureText(this.name); ctx.fillText(this.name, this.xy[0]-text.width/2, this.xy[1] + 12); } } 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); } } function DrawText(xy, text, color, fontSize){ let ctx = staticLayer.getContext("2d"); ctx.font = fontSize + " Verdana"; ctx.fillStyle = color; ctx.fillText( text, xy[0], xy[1]); } ///========================= Floor plan let windowSize = [3840, 2160]; // 4K let sourceLine; { let RFSource1a = new beamRectElement([windowSize[0]*0.9, windowSize[1]*0.9], 0, 40, 100, color.RFsourcce); let RFSource1b = new beamRectElement(RFSource1a.exitPos, 0, 40, 20, color.RFsourcce); let s0 = new beamSpliter(RFSource1b.GetExitPos(120), 80, Math.PI, color.Dipole); let tandem = new tandemClass(RFSource1b.GetExitPos(200), 300, 200, color.Tandem); 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, s0, tandem, q0, df0a, df0b}; } //============ beam line for target room 1 let targetRoom1; { let dipole = new beamDipole(sourceLine.tandem.GetExitPos(300), 80, Math.PI/2, 0, color.Dipole); let fan = new beamSpliter(dipole.GetExitPos(100), 80, -100 * deg, color.Deflector); let upperLine; { //---------- upper beam line 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 GammaStation = new detectorStation(fan.GetExitPos(0.8, 400), "Gamma"); let Catrina = new detectorStation(fan.GetExitPos(0.8, 700), "Carina"); upperLine = {q1a, df1a, GammaStation, Catrina}; } //----------- middle beam line let middleLine; { middleLine = {}; } //----------- lower beam line let lowerLine; { 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 = {q1c, df1c}; } targetRoom1 = {dipole, fan, upperLine, middleLine, lowerLine}; } //================= beam line to target room 2 let targetRoom2; { let q2 = new beamRectElement( sourceLine.tandem.GetExitPos(450), 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(sourceLine.tandem.GetExitPos(900), 80, 90 * deg, 0, color.Dipole); 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(d2.GetExitPos(1700), 100, -100 * deg, color.Dipole); let ResolutLine; { let frac = 0.7; 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(fan2.GetExitPos(frac, 500), 80, 90* deg, -40 * deg, color.Dipole); let b2a_1 = new beamLine( d3.GetExitPos(0), -95 * deg, 500); // dummy let Resolut = new detectorStation(b2a_1.GetExitPos(0), "RESOLUT"); ResolutLine = {df2a_0, q2a, df2a_1, df2a_2, d3, Resolut}; } let AnasenLine; { let frac = 0.5; let q2b = new beamRectElement(fan2.GetExitPos(frac, 150), fan2.GetExitAng(frac), 60, 60, color.Qpole); let df2b = new beamRectElement( fan2.GetExitPos(frac, 240), fan2.GetExitAng(frac), 30, 40, color.Deflector); let Anasen = new detectorStation(fan2.GetExitPos(frac, 500), "Anasen"); AnasenLine = {q2b, df2b, Anasen}; } let lowerLine; { let frac = 0.3; //let b2c = new beamLine(fan2.GetExitPos(frac, 0), fan2.GetExitAng(frac), 500); b2c.offset = 8; 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(fan2.GetExitPos(frac, 500), 80, -130 * deg, color.Dipole); let SplitPoleLine; { let frac = 0.7; 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 detectorStation(fan2c.GetExitPos(frac, 500), "SPS"); SplitPoleLine = {q2c_1, df2c_1a, df2c_1b, SPS}; } let ClarionLine; { let frac = 0.4; 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 detectorStation(fan2c.GetExitPos(frac, 500), "Clarion2"); ClarionLine = {q2c_2, df2c_2a, df2c_2b, Clarion2}; } lowerLine = {q2c, df2c, fan2c, SplitPoleLine, ClarionLine}; } targetRoom2 = {q2, df2, q3, d2, df3, q4, df4, buncher, linac1, linac2, linac3, df5, df6, q5, df7, fan2, ResolutLine, AnasenLine, lowerLine}; } //============================= beam lines let posArray; // thsi is a collection of the position of beamlines { let Gamma = [ sourceLine.RFSource1b.GetExitPos(0), targetRoom1.dipole.entracePos, targetRoom1.dipole.GetExitPos(0), targetRoom1.dipole.GetExitPos(100), targetRoom1.fan.GetExitPos(0.8,0), targetRoom1.fan.GetExitPos(0.8,400) ]; let Catrina = [ sourceLine.RFSource1b.GetExitPos(0), targetRoom1.dipole.entracePos, targetRoom1.dipole.GetExitPos(0), targetRoom1.dipole.GetExitPos(100), targetRoom1.fan.GetExitPos(0.8,0), targetRoom1.fan.GetExitPos(0.8,700) ]; let Middle = [ sourceLine.RFSource1b.GetExitPos(0), targetRoom1.dipole.entracePos, targetRoom1.dipole.GetExitPos(0), targetRoom1.dipole.GetExitPos(100), targetRoom1.fan.GetExitPos(0.55,0), targetRoom1.fan.GetExitPos(0.55,300) ]; let Bottom = [ sourceLine.RFSource1b.GetExitPos(0), targetRoom1.dipole.entracePos, targetRoom1.dipole.GetExitPos(0), targetRoom1.dipole.GetExitPos(100), targetRoom1.fan.GetExitPos(0.35,0), targetRoom1.fan.GetExitPos(0.35,300) ]; let Resolut = [ sourceLine.RFSource1b.GetExitPos(0), targetRoom2.d2.entracePos, targetRoom2.d2.GetExitPos(0), targetRoom2.d2.GetExitPos(1700), targetRoom2.fan2.GetExitPos(0.7, 500), targetRoom2.ResolutLine.d3.GetExitPos(0), targetRoom2.ResolutLine.Resolut.entracePos ] let Anasen = [ sourceLine.RFSource1b.GetExitPos(0), targetRoom2.d2.entracePos, targetRoom2.d2.GetExitPos(0), targetRoom2.d2.GetExitPos(1700), targetRoom2.fan2.GetExitPos(0.5, 500) ] let SPS = [ sourceLine.RFSource1b.GetExitPos(0), targetRoom2.d2.entracePos, targetRoom2.d2.GetExitPos(0), targetRoom2.d2.GetExitPos(1700), targetRoom2.fan2.GetExitPos(0.3, 500), targetRoom2.lowerLine.fan2c.GetExitPos(0.7,500) ] let Clarion2 = [ sourceLine.RFSource1b.GetExitPos(0), targetRoom2.d2.entracePos, targetRoom2.d2.GetExitPos(0), targetRoom2.d2.GetExitPos(1700), targetRoom2.fan2.GetExitPos(0.3, 500), targetRoom2.lowerLine.fan2c.GetExitPos(0.4,500) ] posArray = {Gamma, Catrina, Middle, Bottom, Resolut, Anasen, SPS, Clarion2}; } let beamLineHaHa; { let Gamma = new multiBeamLine(posArray.Gamma); let Catrina = new multiBeamLine(posArray.Catrina); let Middle = new multiBeamLine(posArray.Middle); let Bottom = new multiBeamLine(posArray.Bottom); let Resolut = new multiBeamLine(posArray.Resolut); let Anasen = new multiBeamLine(posArray.Anasen); let SPS = new multiBeamLine(posArray.SPS); let Clarion2 = new multiBeamLine(posArray.Clarion2); beamLineHaHa = {Gamma, Catrina, Middle, Bottom, Resolut, Anasen, SPS, Clarion2}; } //============================== Draw var destination = 'Gamma'; function DisableAllDetector(){ for( const ele in beamLineHaHa){ beamLineHaHa[ele].draw(false); } for( const ele in sourceLine){ sourceLine[ele].draw(true); } for( const ele in targetRoom1){ try{ targetRoom1[ele].draw(false); }catch(err){ for( const haha in targetRoom1[ele]){ try{ targetRoom1[ele][haha].draw(false); }catch(err){ } } } } 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 EnableDetector(){ DisableAllDetector(); if( destination == 'Gamma' ) targetRoom1.upperLine.GammaStation.draw(true); if( destination == 'Catrina') targetRoom1.upperLine.Catrina.draw(true); if( destination == 'RESOLUT') targetRoom2.ResolutLine.Resolut.draw(true); if( destination == 'Anasen') targetRoom2.AnasenLine.Anasen.draw(true); if( destination == 'SPS') targetRoom2.lowerLine.SplitPoleLine.SPS.draw(true); if( destination == 'Clarion2') targetRoom2.lowerLine.ClarionLine.Clarion2.draw(true); if( destination == 'Gamma' || destination == 'Catrina'){ for( const ele in targetRoom1){ try{ targetRoom2[ele].draw(true); }catch(err){ } } } if( destination == 'RESOLUT' || destination == 'Anasen' || destination == 'SPS' || destination == 'Clarion2'){ for( const ele in targetRoom2){ try{ targetRoom2[ele].draw(true); }catch(err){ } } } if( destination == 'RESOLUT'){ for( const ele in targetRoom2.ResolutLine){ try{ targetRoom2.ResolutLine[ele].draw(true); }catch(err){ } } } } function lineMotion(){ if( destination == 'Gamma' ) beamLineHaHa.Gamma.march(); if( destination == 'Catrina') beamLineHaHa.Catrina.march(); if( destination == 'RESOLUT') beamLineHaHa.Resolut.march(); if( destination == 'Anasen') beamLineHaHa.Anasen.march(); if( destination == 'SPS') beamLineHaHa.SPS.march(); if( destination == 'Clarion2') beamLineHaHa.Clarion2.march(); setTimeout(lineMotion, 50); } //EnableDetector(); //lineMotion();