Главная | Описание языка | FXD | API | Примеры | Инструменты Разработки | Новости | Ресурсы | Форум
Разлет частиц[]
Релятивистский случай[]
Теорема косинусов в геометрии Лобачевского:
Вторая теорема косинусов:
Столкновение частиц. Расчеты проводятся на карте скоростей процесса. Таким образм, если отвечает длине вектора скорости на карте в системе центра масс, то выполнены следущие равенства:
, импульс частицы, , энергия, , скорость часицы, относительно скорости света.
Закон сохранения импульса и энергии:
Из этих законов можно заметить, что v1=v1' и v2=v2'.
Релятивистская формула сложения скоростей:
, где с - скорость света.
В лабораторной системе отсчета известна только скорость налетающей частицы-AB, с помощью масс можно найти скорости v1 и v2, для этого будем использовать 3 формулы: если AO обозначить за a, OB за b, а AB за c (c=a+b), то v1=th\ a, v2=th\ b, и в системе центра масс импульс системы равен 0, т.е. модули импульсов равны, откуда
(релятивисткое правило рычага), т.е.
Далее рассмотрим формулы синуса и косинуса суммы в гиперболической тригонометрии:
выразим из второй формулы ch b:
подставляем это выражение в первую формулу, заменяем sh b по правилу рычага:
Аналогично
Далее, по теореме косинусов можно найти скорости отлета c и c' и углы при них в лабораторной системе отсчета и :
Отсюда получаем скорость в координатной системе:
Полная программа:
import javafx.animation.*;
import javafx.application.*;
import javafx.ext.swing.*;
import javafx.scene.*;
import javafx.scene.paint.*;
import javafx.scene.geometry.*;
import javafx.scene.transform.*;
import javafx.scene.text.*;
import javafx.scene.image.ImageView;
import javafx.scene.image.Image;
import java.lang.Math;
import java.lang.*;
import java.lang.System;
import javafx.input.*;
import javafx.input.MouseEvent;
var disang:Number;
var r=0;
var nu=1;
var h=6.6256e-34;
var c=299792458;
var v = 0.11;//скорость налетающей частицы относительно скорости света
var sp=0.0 ;
var l=2;
var protonMass = 0.1;
var electronMass = 0.01;
var tests = [
TestCase{
angle: 0.0
result1: Particle{
name: "Result Proton 1"
angle: 0.0
speed: 0.0
}
result2: Particle{
name: "Result Proton 2"
angle: 0.0
speed: 0.5
}
}
];
var timeline = Timeline {
keyFrames: KeyFrame { time: 0.01s, action: function() { particleSystem.run()
} }
repeatCount: java.lang.Double.POSITIVE_INFINITY
}
var particleSystem = ParticleSystem{
transform: Transform.translate(400, 300)
particles: [
Particle{
name: "Particle 1"
mass: 10
radius: 4
startx: -146
starty: 0
speed: 0.5
color: Color.GREEN
},
Particle{
name: "Particle 2"
mass: 10
radius: 4
startx: 0
starty: 0
speed: 0
color: Color.RED
}
]
};
function abs (x:Number):Number {
return if ( 0 < x ) then x else -x;
}
function q (w:Number):Number{//возведение в квадрат
return w*w
}
function arth (x:Number):Number{//обратная к гиперболическому тангенсу
return if (x==1) 1
else Math.log((1+x)/(1-x))/2
}
function arch (x:Number):Number{//~косинуа
return Math.log(x+Math.sqrt(q(x)-1))
}
function arsh (x:Number):Number{//~синуса
return Math.log(x+Math.sqrt(q(x)+1))
}
function tch (ang:Number, v1:Number, v2:Number):Number{//по теореме косинусов находит сторону по сторонам и углу
return if (ang==0) Math.tanh(abs(arth(v1)-arth(v2)))
else if (ang==Math.PI) (v1+v2)/(1+v1*v2)
else round(Math.tanh(arch((Math.cosh(arth(v1))*Math.cosh(arth(v2))-Math.sinh(arth(v1))*Math.sinh(arth(v2))*Math.cos(ang)))),3);
}
function tch1 (v1:Number, v2:Number, v3:Number):Number{//по теореме косинусов находим угол разлета
return if (v3==0) 0
else if (v2==0) 0
else if (v1==0) 0
else round(Math.acos((Math.cosh(arth(v1))*Math.cosh(arth(v2))-Math.cosh(arth(v3)))/Math.sinh(arth(v1))/Math.sinh(arth(v2))),3)
}
function round (N:Number,n:Number):Number{
var a=1;
for (i in [1..n]) {a=a*10; }
var b=N*a;
b=Math.round(b);
return b/a
}
function sub(p1:Particle, angle:Number,speed:Number){
var b1=p1.speed*Math.cos(p1.angle);
System.out.println('b1='+b1);
var b2=speed*Math.cos(angle);
System.out.println('b2='+b2);
System.out.println(speed);
System.out.println(angle);
var b=(b2-b1)/(1-b1*b2);
System.out.println('b='+b);
var a1=Math.tanh(arsh(Math.sinh(arth(p1.speed))*Math.sin(p1.angle)));
var a2=Math.tanh(arsh(Math.sinh(arth(speed))*Math.sin(angle)));
var a=(a2-a1)/(1-a1*a2);
System.out.println('a='+ a);
p1.speed=tch(Math.PI/2,a,b);
System.out.println('ps='+ p1.speed);
p1.angle=Math.atan(a/Math.sinh(arth(b)));
System.out.println('pa='+ p1.angle);
if (b<0)p1.angle=Math.PI+p1.angle;
// if (a>0){if (b>0) p1.angle=abs(p1.angle) else }
}
/*function sub(p1:Particle, angle:Number,speed:Number){
var pspeed=p1.speed;
p1.speed=tch(p1.angle-angle,p1.speed,speed);
if (p1.angle>angle){
if(p1.angle-angle<=Math.PI){
System.out.println("***1***");
p1.angle=angle+tch1(speed,p1.speed,pspeed);
}
else {
System.out.println("***2***");
p1.angle=angle-tch1(speed,p1.speed,pspeed);
}
}
else {
if (angle-p1.angle<=Math.PI){
System.out.println("***3***");
p1.angle=angle-tch1(speed,p1.speed,pspeed);
}
else{
System.out.println("***4***");
p1.angle=angle+tch1(speed,p1.speed,pspeed);
}
}
System.out.println(p1.angle);
System.out.println(p1.speed);
System.out.println(pspeed);
}*/
function line (p1:Particle,p2:Particle, ang:Number){
System.out.println("angel1="+p1.angle);
System.out.println("2="+p2.angle);
p1.angle=ang;
p2.angle=Math.PI+ang;
System.out.println("angel="+ang)
}
function line_for_foton (p1:Particle, p2:Particle, ang:Number){
if (p1.speed==1){
if (not(p2.speed==1)) p1.angle=Math.random()*Math.PI*2
}
else p2.angle=Math.random()*Math.PI*2
}
function start (p1:Particle,p2:Particle, ang:Number){
if (p1.angle==p2.angle) v=(p1.speed+p2.speed)/(1+p1.speed*p2.speed)
else
v=tch(p1.angle-p2.angle,p1.speed,p2.speed);
System.out.println("v="+v);
var v1=p2.mass*Math.sinh(arth(v))/(p1.mass+p2.mass*Math.cosh(arth(v)));
System.out.println("v1="+v1);
var v2=p1.mass*Math.sinh(arth(v))/(p2.mass+p1.mass*Math.cosh(arth(v)));
System.out.println("v2="+v2);
var speed=tch(tch1(v,p1.speed,p2.speed),v1,p1.speed);
System.out.println("speed="+speed);
var angle;
var dopang;
var pang;
if (p1.speed==0){pang=p2.angle;} else pang=p1.angle;
if (p1.angle>p2.angle){//пока правильно-угол е-8
if(p1.angle-p2.angle<=Math.PI){
angle=p1.angle-tch1(p1.speed,speed,v1);
//dopang=p1.angle-tch1(p1.speed,v,p2.speed);
System.out.println("***1***");
System.out.println("p2.angle="+p2.angle);
System.out.println(p1.speed);
System.out.println(speed);
System.out.println(v1);
System.out.println(tch1(p1.speed,speed,v1));
}
else {
angle=p1.angle+tch1(p1.speed,speed,v1);
//dopang=p2.angle-tch1(p2.speed,v,p1.speed);
System.out.println("***2***");
System.out.println("p2.angle="+p2.angle);
System.out.println(p1.speed);
System.out.println(speed);
System.out.println(v1);
System.out.println(tch1(p1.speed,speed,v1));
}
}
else {
if (p2.angle-p1.angle<=Math.PI){
angle=pang+tch1(p1.speed,speed,v1);
//dopang=p2.angle-tch1(p2.speed,v,p1.speed);
System.out.println("***3***");
System.out.println("p2.angle="+p2.angle);
System.out.println("dop="+dopang);
System.out.println(p1.speed);
System.out.println(speed);
System.out.println(v1);
System.out.println(tch1(p1.speed,speed,v1));
}
else{
angle=pang-tch1(p1.speed,speed,v1);
//dopang=p1.angle-tch1(p1.speed,v,p2.speed);
System.out.println("***4***");
System.out.println("p2.angle="+p2.angle);
System.out.println(p1.speed);
System.out.println(speed);
System.out.println(v1);
System.out.println(tch1(p1.speed,speed,v1));
}
};
System.out.println("angle="+angle);
{ var p1s=p1.speed;
var p1a=p1.angle;
sub (p1,p2.angle,p2.speed);
dopang=p1.angle;
System.out.println("dopang="+dopang);
System.out.println("v="+p2.speed);
p1.speed=p1s;
p1.angle=p1a;}
p1.speed=v1;
p2.speed=v2;
p1.angle=0;
p2.angle=0;
line(p1,p2,ang);
p1.angle=p1.angle+dopang;
p2.angle=p2.angle+dopang;
System.out.println("p1.angle "+p1.angle);
System.out.println("p2.angle "+p2.angle);
System.out.println("p1.speed "+p1.speed);
System.out.println("p2.speed "+p2.speed);
sub(p1,angle,speed);
sub(p2,angle,speed);
System.out.println("1 "+p1.angle);
System.out.println("2 "+p2.angle);
/* var angle=p2.angle+Math.PI;
var speed=p2.speed;
if (angle<0) angle+=2*Math.PI;
System.out.println(p2.angle);
System.out.println(p1.dX);
sub(p1,p2.angle, p2.speed);
sub(p2,p2.angle, p2.speed);
if (p1.speed==1 or p2.speed==1){
line_for_foton (p1,p2,ang);
} else {
line(p1,p2, ang);
}
sub(p1,angle, speed);
sub(p2,angle, speed);
*/
}
public class Particle{//класс частиц
public attribute name:String ;
public attribute speed:Number on replace {if (speed==0) angle=0};
public attribute startspeed:Number;
public attribute color:Color;
public attribute x:Number ;
public attribute y:Number ;
public attribute dX=bind Math.cos(angle)*speed*10/sp ;
public attribute startx:Number on replace{ x = startx; };
public attribute starty:Number on replace{ y = starty; };
public attribute radius:Number ;
public attribute mass:Number on replace {if (mass==0) speed=1};
public attribute dY=bind Math.tanh(arsh(Math.sinh(arth(speed))*Math.sin(angle)))*10/sp;
public attribute angle:Number;
public attribute startangle:Number;
public attribute flag=0;
public attribute flag2=0;
public function compare(p:Particle, eps:Number):Boolean{
return (p.speed == 0.0 and speed == 0.0) or ( abs(p.angle - angle) < eps and abs(p.speed - speed) < eps );
}
public function toString():String{
var res = "Particle\{\n";
res += "name: {name}\n";
res += "angle: {angle}\n";
res += "speed: {speed}\n";
res += "}";
return res;
}
}
public class ParticleSystem extends CustomNode{//сама модель
public attribute particles: Particle[];
public attribute dt:Number = 0.05 ;
public function run () {
for (particle in particles){
sp = Math.max(sp,particle.speed);
if (particle.flag2==0){
particle.flag2++;
particle.startangle=particle.angle;
particle.startspeed=particle.speed;
particle.startx=particle.x;
particle.starty=particle.y;
}
}
for (particle1 in particles){
for (particle2 in particles[
particle| particle != particle1]){
var minDistance = particle1.radius + particle2.radius;
if( Math.sqrt(q(particle1.x - particle2.x)+q(particle1.y - particle2.y)) < minDistance and particle1.flag==0 and particle2.flag==0){//столкновение
particle1.flag=1;
particle2.flag=1;
System.out.println("Particle collision!");
start(particle1, particle2, disang);
/*for(test in tests){
test.particle1=particle1;
test.particle2=particle2;
start(test.particle1, test.particle2, test.angle);
test.compare();} */
}
if ( Math.sqrt(q(particle1.x - particle2.x)+q(particle1.y - particle2.y)) > minDistance and ((particle1.flag==1) or (particle2.flag==1))){
particle1.flag=0;
particle2.flag=0;
}
}
}
for (particle in particles){//движение
if (particle.angle<0) {particle.angle+=2*Math.PI;}
if (particle.angle>=2*Math.PI) {particle.angle-=2*Math.PI;}
particle.x = particle.dX * dt *r + particle.x;
particle.y = particle.dY * dt *r + particle.y;
for (particle1 in particles){ //торможение
for (particle2 in particles){
if (Math.sqrt(particle1.x*particle1.x+particle1.y*particle1.y)>150 or (
Math.sqrt(particle2.x*particle2.x+particle2.y*particle2.y)>150))
{
particle1.speed=0;
particle2.speed=0;
}
}
}
}
}
function create():Node{
return Group{
content:bind [ for (particle in particles){
Circle{
radius: particle.radius
fill: bind particle.color
centerX: bind particle.x
centerY: bind particle.y
onMouseDragged: function( e: MouseEvent ){
particle.startx = e.getX();
particle.x=e.getX();
particle.starty = e.getY();
particle.y = e.getY();
}
}
}
]
}
}
}
public class SetupParticleSystem extends CustomNode{
public attribute particles:Particle[];
attribute ang:String on replace {
disang = java.lang.Double.parseDouble(ang);
};
attribute index:Integer on replace{
mass = "{particles[index].mass}";
speed = "{particles[index].speed}";
x = "{particles[index].x}";
y = "{particles[index].y}";
angle = "{particles[index].angle}";
};
attribute mass:String on replace{
particles [index].mass = java.lang.Double.parseDouble(mass);
};
attribute speed:String on replace{
particles [index].speed = java.lang.Double.parseDouble(speed);
particles [index].startspeed = java.lang.Double.parseDouble(speed);
};
attribute x:String on replace{
particles [index].x = java.lang.Double.parseDouble(x);
};
attribute angle:String on replace{
particles [index].angle = java.lang.Double.parseDouble(angle);
particles [index].startangle = java.lang.Double.parseDouble(angle);
};
attribute y:String on replace{
particles [index].y = java.lang.Double.parseDouble(y);
};
function create():Node{
return ComponentView {
component: BorderPanel{
left: List{
items: bind
for (particle in particles)
ListItem{
text: particle.name
}
selectedIndex: bind index with inverse
}
center: FlowPanel{ content: GridPanel{
columns: 3, rows: 6
content: [
Label{ text: "Mass"},
TextField{ columns: 7, text: bind mass with inverse},
Label {},
Label{ text: "Speed"},
TextField{ columns: 7, text: bind speed with inverse},
Label{ text: bind "{%+10.4f particles[index].speed}"},
Label{ text: "Coordinate x"},
TextField{ columns: 7, text: bind x with inverse},
Label{ text: bind "{%+10.4f particles[index].x}"},
Label{ text: "Coordinate y"},
TextField{ columns: 7, text: bind y with inverse},
Label{ text: bind "{%+10.4f particles[index].y}"},
Label{ text: "Angle"},
TextField{ columns: 7, text: bind angle with inverse},
Label{ text: bind "{%+10.4f particles[index].angle}"},
Label{ text: "DisAng"},
TextField{ columns: 7, text: bind ang with inverse},
Label {},
]
} }
right: FlowPanel{ content: GridPanel{
rows: 3
content:[
Button{
text: bind if(r==1) then "Pause" else "Run"
action: function(){timeline.start();
r=1-r;}
},
Button{
text: "Reset"
action:function(){
for (particle in particles){
particle.x=particle.startx;
particle.y=particle.starty;
particle.speed=particle.startspeed;
particle.angle=particle.startangle;
particle.flag=0;
particle.flag2=0;
sp=0;
}}
},
Button{
text: "Add"
action:function(){l++; insert Particle{
name: "Particle "+l
startx: (Math.random()-0.5)*200
starty: (Math.random()-0.5)*200
radius: 4
mass: 10
color: Color.rgb(Math.random()*255, Math.random()*255, Math.random()*255)
} into particles;
} }]
}
}}
}
}
}
public class TestCase{
public attribute eps:Number = 0.1;
public attribute angle: Number;
public attribute particle1: Particle;
public attribute particle2: Particle;
public attribute result1: Particle;
public attribute result2: Particle;
public function print(p: Particle, res:Particle){
System.out.println("=========== Particles are not equal =============");
System.out.println("particle: {p}");
System.out.println("result: {res}");
}
public function compare(){
if(not result1.compare(particle1, eps)){
print(particle1, result1);
}
if(not result2.compare(particle2, eps)){
print(particle2, result2);
}
}
}
function angle(x1:Number, y1:Number, x2:Number, y2:Number):Number{
var scalar = x1 * x2 + y1 * y2;
var length1 = Math.sqrt(x1 * x1 + y1 * y1);
var length2 = Math.sqrt(x2 * x2 + y2 * y2);
return Math.acos( scalar / ( length1 * length2));
}
function speedpt(ang1:Number, ang2:Number, m1:Number, m2:Number):Number{
var a = Math.sin(ang1)/Math.sin(ang1+ang2)*m1/m2;
var b = Math.sin(ang2)/Math.sin(ang1+ang2);
var c = q(q(b)-q(a))+1-(q(a)+q(b))*2;
var p = (-q(q(b)-q(a))+1)*2;
var z = q(q(a)-q(b))-3+(q(b)+q(a))*2;
var x = (-p-Math.sqrt(q(p)-c*z*4))/(c*2);
return Math.sqrt(1-1/q(x))
}
public class RotatedLine extends CustomNode{
public attribute color:Color;
public attribute name:String;
public attribute reflect:Boolean;
public attribute centerX:Number;
public attribute centerY:Number;
public attribute startX:Number;
public attribute startY:Number;
public function create(){
Group{
content:[
Line{
startX: bind centerX
startY: bind centerY
endX: bind centerX + startX
endY: bind centerY + startY
},
Circle{
centerX: bind centerX + startX
centerY: bind centerY + startY
radius: 5
fill: bind color
onMouseDragged: function( e: MouseEvent ):Void {
startX = e.getX() - centerX;
startY = e.getY() - centerY;
}
},Text{
x: bind centerX + startX + 5
y: bind centerY + startY - 5
fill: Color.RED
font: Font { size: 16 style: FontStyle.PLAIN }
content: name
},
if (reflect)
Line{
startX: bind centerX
startY: bind centerY
endX: bind centerX - startX
endY: bind centerY - startY
strokeDashArray: [ 10.0 ]
} else []
]
}
}
}
public class ParticleImage extends CustomNode{
public attribute url: String;
public attribute color:Color = Color.CORAL;
public attribute lineColor:Color = Color.CORAL;
public attribute scale:Number = 1.0;
public attribute angle1:Number = bind angle(-startX, -startY, endX1, endY1);
public attribute angle2:Number = bind angle(-startX, -startY, endX2, endY2);
public attribute speed:Number = bind speedpt(angle1,angle2, java.lang.Double.parseDouble(mass1), java.lang.Double.parseDouble(mass2));
public attribute disangle:Number = bind tch1(v1,v1,v2);/*bind 2*Math.atan(Math.sqrt(Math.tan(angle1)/Math.tan(angle2)));*/
public attribute mass1: String="1";
public attribute mass2: String="1";
attribute m1=bind java.lang.Double.parseDouble(mass1);
attribute m2=bind java.lang.Double.parseDouble(mass2);
attribute v2=bind Math.tanh (arsh(m1/m2*Math.sinh(arth(speed))*Math.sin(angle1)/Math.sin(angle1+angle2)));
attribute v1=bind m1*Math.sinh(arth(speed))/(m2+m1*Math.cosh(arth(speed)));
attribute centerX:Number = 50;
attribute centerY:Number = 50;
attribute startX:Number = -140;
attribute startY:Number = 0;
attribute endX1:Number = 90;
attribute endY1:Number = -90;
attribute endX2:Number = 90;
attribute endY2:Number = 90;
public function create():Node{
return {Group{
transform: Scale{ x: bind scale y: bind scale}
onMouseWheelMoved: function( e: MouseEvent ){
var s = -e.getWheelRotation();
scale += s / 10;
}
content:[
ComponentView {
component: GridPanel{
rows: 2 columns: 2
content: [ Label{ text: "Mass1"},
TextField{ columns: 7, text: bind mass1 with inverse},
Label{ text: "Mass2"},
TextField{ columns: 7, text: bind mass2 with inverse},]
}
},
ImageView {
image: bind Image {
url: url
}
},
Circle{
centerX: bind centerX
centerY: bind centerY
radius: 20
opacity: 0.01
fill: Color.WHITE
onMouseDragged: function( e: MouseEvent ){
centerX = e.getX();
centerY = e.getY();
}
},
Circle{
centerX: bind centerX
centerY: bind centerY
radius: 20
stroke: bind color
},
Circle{
centerX: bind centerX
centerY: bind centerY
radius: 120
stroke: bind color
},
RotatedLine{
name: "0"
reflect: true
centerX: bind centerX
centerY: bind centerY
startX: bind startX with inverse
startY: bind startY with inverse
color: lineColor
},
RotatedLine{
name: "1"
centerX: bind centerX
centerY: bind centerY
startX: bind endX1 with inverse
startY: bind endY1 with inverse
color: lineColor
},
RotatedLine{
name: "2"
centerX: bind centerX
centerY: bind centerY
startX: bind endX2 with inverse
startY: bind endY2 with inverse
color: lineColor
},
Text{
x: 10
y: -100
fill: lineColor
content: bind "Angle 1: {%10.5f angle1}"
},
Text{
x: 10
y: -70
fill: lineColor
content: bind "Angle 2: {%10.5f angle2}"
},
Text{
x:10
y:-40
fill: lineColor
content: bind "Speed: {%10.5f speed}"
},
Text{
x: 10
y: -10
fill: lineColor
content: bind "DispAngle: {%10.5f disangle}"
},
/*GridPanel{
columns: 2, rows: 2
content: [
Label{ text: "Mass1"},
TextField{ columns: 7, text: bind mass1 with inverse},
Label{ text: "Mass2"},
TextField{ columns: 7, text: bind mass2 with inverse},
]
}*/
]
}
}
}
}
public class ImageItem{
attribute name:String;
attribute path:String;
}
var images = [ImageItem{ name: "Emission"}, ImageItem{ name: "Protons" path: "protons.png"}];
var imageIndex = 1;
var imageGroup = Group{
content:[
ParticleImage{
translateY: 170
centerX: 200
centerY: 200
url: bind "{__DIR__}{images[imageIndex].path}"
color: Color.GREEN
},
]
};
var group = Group{
content: [
SetupParticleSystem{ particles:bind particleSystem.particles with inverse},
particleSystem
]
};
Frame{
title: "Particle Collision"
width: 800
height: 600
closeAction: function(){
System.exit(0);
}
stage: Stage{
content: [
Group{
content: bind [
ComponentView{
translateX: 460
translateY: 140
component: ComboBox {
items: for (image in images)
ComboBoxItem {
text: image.name
selected: true
}
selectedIndex: bind imageIndex with inverse
}
}, if(0 < imageIndex )
ParticleImage{
translateY: 170
centerX: 200
centerY: 200
url: bind "{__DIR__}{images[imageIndex].path}"
color: Color.GREEN
}
else group,
/*if (imageIndex==0)[
SetupParticleSystem{ particles:bind particleSystem.particles with inverse},
particleSystem] else []*/
]
},
]
}
visible: true
}
Тестовые примеры:
public class Particle{//класс частиц
public attribute startspeed:Number on replace { speed = startspeed; };
public attribute startangle:Number on replace { angle = startangle; };
}
var tests = [
TestCase{
// p1 -> p2
// centre mass angle = 0
// p1 speed: 0.5, angle = 0
// p2 speed: 0, angle = 0
angle: Math.PI // or 0.0 ?
particle1: Particle{
name: "I - Proton 1"
startx: -50
mass: electronMass
startangle: 0.0
startspeed: 0.5
}
particle2: Particle{
name: "I - Proton 2"
startx: 50
mass: electronMass
startangle: 0.0
startspeed: 0.0
}
result1: Particle{
name: "I - Result Proton 1"
angle: 0.0
speed: 0.0
}
result2: Particle{
name: "I - Result Proton 2"
angle: 0.0
speed: 0.5
}
},
TestCase{
// p1 <- p2
// centre mass angle = 0
// p1 speed: 0, angle = 0
// p2 speed: 0.5, angle = PI
angle: Math.PI // 0.0
particle1: Particle{
name: "II - Proton 1"
startx: -50
mass: electronMass
startangle: 0.0
}
particle2: Particle{
name: "II - Proton 2"
startx: 50
mass: electronMass
startangle: Math.PI
startspeed: 0.5
}
result1: Particle{
name: "II - Result Proton 1"
angle: 0.0
speed: 0.5
}
result2: Particle{
name: "II - Result Proton 2"
angle: 0.0
speed: 0.0
}
},
TestCase{
// p2
// ^
// |
// p1
// centre mass angle = 0
// p1 speed: 0.5, angle = PI / 2
// p2 speed: 0, angle = 0
angle: Math.PI // 0.0
particle1: Particle{
name: "III - Proton 1"
startx: 0.0
starty: -50.0
mass: electronMass
startangle: Math.PI / 2
startspeed: 0.5
}
particle2: Particle{
name: "III - Proton 2"
startx: 50
mass: electronMass
startangle: 0.0
startspeed: 0.0
}
result1: Particle{
name: "III - Result Proton 1"
angle: 0.0
speed: 0.0
}
result2: Particle{
name: "III - Result Proton 2"
angle: Math.PI / 2
speed: 0.5
}
},
TestCase{
// p1 -> <- p2
// centre mass angle = 0
// p1 speed: 0.5, angle = 0
// p2 speed: 0.5, angle = PI
angle: Math.PI // 0.0
particle1: Particle{
name: "IV - Proton 1"
startx: -50
mass: electronMass
startangle: 0
startspeed: 0.5
}
particle2: Particle{
name: "IV - Proton 2"
startx: 50
mass: electronMass
startangle: Math.PI
startspeed: 0.5
}
result1: Particle{
name: "IV - Result Proton 1"
angle: 0.0
speed: 0.0
}
result2: Particle{
name: "IV - Result Proton 2"
angle: 0
speed: 0
}
},
];
for(test in tests){
start(test.particle1, test.particle2, test.angle);
test.compare();
}
Определение угла разлета частиц на фотоснимке[]
Фотоснимок сталкивающихся протонов:
Увеличение фотоснимка и определение углов разлета частиц:
Программа:
import javafx.application.Frame;
import javafx.application.Stage;
import javafx.scene.*;
import javafx.scene.paint.*;
import javafx.scene.text.*;
import javafx.scene.geometry.*;
import javafx.scene.transform.*;
import javafx.scene.image.ImageView;
import javafx.scene.image.Image;
import javafx.input.MouseEvent;
import java.lang.Math;
import java.lang.System;
function q (w:Number):Number{//возведение в квадрат
return w*w
}
function arch (x:Number):Number{//~косинуа
return Math.log(x+Math.sqrt(q(x)-1))
}
function angle(x1:Number, y1:Number, x2:Number, y2:Number):Number{
var scalar = x1 * x2 + y1 * y2;
var length1 = Math.sqrt(x1 * x1 + y1 * y1);
var length2 = Math.sqrt(x2 * x2 + y2 * y2);
return Math.acos( scalar / ( length1 * length2));
}
function speedpt(ang1:Number, ang2:Number):Number{
var a = Math.sin(ang1)/Math.sin(ang1+ang2);
var b = Math.sin(ang2)/Math.sin(ang1+ang2);
var c = q(q(b)-q(a))+1-(q(a)+q(b))*2;
var p = (-q(q(b)-q(a))+1)*2;
var z = q(q(a)-q(b))-3+(q(b)+q(a))*2;
var x = (-p-Math.sqrt(q(p)-c*z*4))/(c*2);
return Math.sqrt(1-1/q(x))
}
class RotatedLine extends CustomNode{
public attribute color:Color;
public attribute name:String;
public attribute reflect:Boolean;
public attribute centerX:Number;
public attribute centerY:Number;
public attribute startX:Number;
public attribute startY:Number;
public function create(){
Group{
content:[
Line{
startX: bind centerX
startY: bind centerY
endX: bind centerX + startX
endY: bind centerY + startY
},
Circle{
centerX: bind centerX + startX
centerY: bind centerY + startY
radius: 5
fill: bind color
onMouseDragged: function( e: MouseEvent ):Void {
startX = e.getX() - centerX;
startY = e.getY() - centerY;
}
},Text{
x: bind centerX + startX + 5
y: bind centerY + startY - 5
fill: Color.RED
font: Font { size: 16 style: FontStyle.PLAIN }
content: name
},
if (reflect)
Line{
startX: bind centerX
startY: bind centerY
endX: bind centerX - startX
endY: bind centerY - startY
strokeDashArray: [ 10.0 ]
} else []
]
}
}
}
class ParticleImage extends CustomNode{
public attribute url: String;
public attribute color:Color = Color.CORAL;
public attribute lineColor:Color = Color.CORAL;
public attribute scale:Number = 1.0;
public attribute angle1:Number = bind angle(-startX, -startY, endX1, endY1);
public attribute angle2:Number = bind angle(-startX, -startY, endX2, endY2);
public attribute speed:Number = bind speedpt(angle1,angle2);
public attribute disangle:Number = bind 2*Math.atan(Math.sqrt(Math.tan(angle1)/Math.tan(angle2)));
attribute centerX:Number = 50;
attribute centerY:Number = 50;
attribute startX:Number = -140;
attribute startY:Number = 0;
attribute endX1:Number = 90;
attribute endY1:Number = -90;
attribute endX2:Number = 90;
attribute endY2:Number = 90;
public function create(){
Group{
transform: Scale{ x: bind scale y: bind scale}
onMouseWheelMoved: function( e: MouseEvent ){
var s = -e.getWheelRotation();
scale += s / 10;
}
content:[
ImageView {
image: Image {
url: url
}
},
Circle{
centerX: bind centerX
centerY: bind centerY
radius: 20
opacity: 0.01
fill: Color.WHITE
onMouseDragged: function( e: MouseEvent ){
centerX = e.getX();
centerY = e.getY();
}
},
Circle{
centerX: bind centerX
centerY: bind centerY
radius: 20
stroke: bind color
},
Circle{
centerX: bind centerX
centerY: bind centerY
radius: 120
stroke: bind color
},
RotatedLine{
name: "0"
reflect: true
centerX: bind centerX
centerY: bind centerY
startX: bind startX with inverse
startY: bind startY with inverse
color: lineColor
},
RotatedLine{
name: "1"
centerX: bind centerX
centerY: bind centerY
startX: bind endX1 with inverse
startY: bind endY1 with inverse
color: lineColor
},
RotatedLine{
name: "2"
centerX: bind centerX
centerY: bind centerY
startX: bind endX2 with inverse
startY: bind endY2 with inverse
color: lineColor
},
Text{
x: 10
y: 50
fill: lineColor
content: bind "Angle 1: {%10.5f angle1}"
},
Text{
x: 10
y: 80
fill: lineColor
content: bind "Angle 2: {%10.5f angle2}"
},
Text{
x:10
y:110
fill: lineColor
content: bind "Speed: {%10.5f speed}"
},
Text{
x: 10
y: 140
fill: lineColor
content: bind "DispAngle: {%10.5f disangle}"
}
]
}
}
}
Frame {
title: "MyApplication"
width: 600
height: 500
closeAction: function() {
java.lang.System.exit( 0 );
}
visible: true
stage: Stage {
content: [
ParticleImage{
centerX: 200
centerY: 200
url: "{__DIR__}protons.jpg"
color: Color.GREEN
}
]
}
}
Определение угла разлета частиц на фотоснимке - Полная программа[]
import javafx.animation.*;
import javafx.application.*;
import javafx.ext.swing.*;
import javafx.scene.*;
import javafx.scene.paint.*;
import javafx.scene.geometry.*;
import javafx.scene.transform.*;
import java.lang.Math;
import java.lang.*;
import java.lang.System;
import javafx.input.*;
var r=0;
var nu=1;
var h=6.6256e-34;
var c=299792458;
var v = 0.11;//скорость налетающей частицы относительно скорости света
var sp=0.0 ;
var l=2;
var protonMass = 0.1;
var electronMass = 0.01;
var tests = [
TestCase{
angle: 0.0
result1: Particle{
name: "Result Proton 1"
angle: 0.0
speed: 0.0
}
result2: Particle{
name: "Result Proton 2"
angle: 0.0
speed: 0.5
}
}
];
var timeline = Timeline {
keyFrames: KeyFrame { time: 0.01s, action: function() { particleSystem.run()
} }
repeatCount: java.lang.Double.POSITIVE_INFINITY
}
var particleSystem = ParticleSystem{
transform: Transform.translate(400, 300)
particles: [
Particle{
name: "Particle 1"
mass: 10
radius: 4
startx: -146
starty: 0
speed: 0.5
color: Color.GREEN
},
Particle{
name: "Particle 2"
mass: 10
radius: 4
startx: 0
starty: 0
speed: 0
color: Color.RED
}
]
};
function abs (x:Number):Number {
return if ( 0 < x ) then x else -x;
}
function q (w:Number):Number{//возведение в квадрат
return w*w
}
function arth (x:Number):Number{//обратная к гиперболическому тангенсу
return if (x==1) 1
else Math.log((1+x)/(1-x))/2
}
function arch (x:Number):Number{//~косинуа
return Math.log(x+Math.sqrt(q(x)-1))
}
function arsh (x:Number):Number{//~синуса
return Math.log(x+Math.sqrt(q(x)+1))
}
function tch (ang:Number, v1:Number, v2:Number):Number{//по теореме косинусов находит сторону по сторонам и углу
return if (ang==0) 0
else if (ang==Math.PI) (v1+v2)/(1+v1*v2)
else Math.tanh(arch((Math.cosh(arth(v1))*Math.cosh(arth(v2))-Math.sinh(arth(v1))*Math.sinh(arth(v2))*Math.cos(ang))));
}
function tch1 (v1:Number, v2:Number, v3:Number):Number{//по теореме косинусов находим угол разлета
return if (v3==0) 0
else if (v2==0) 0
else if (v1==0) 0
else Math.acos((Math.cosh(arth(v1))*Math.cosh(arth(v2))-Math.cosh(arth(v3)))/Math.sinh(arth(v1))/Math.sinh(arth(v2)))
}
function sub (p1:Particle, angle:Number, speed:Number){
var pspeed=p1.speed;
System.out.println("pspeed="+pspeed);
p1.speed=tch(p1.angle-angle,p1.speed,speed);
System.out.println(p1.name+".speed="+p1.speed);
System.out.println(p1.name+".angle="+p1.angle);
System.out.println("angle="+angle);
System.out.println("speed="+speed);
if (p1.angle>angle) p1.angle-=tch1(pspeed,p1.speed,speed)
else p1.angle+=tch1(pspeed,p1.speed,speed)-2*Math.PI;
for (p in [p1]){
if (p.angle<0) {p.angle+=2*Math.PI;}
if (p.angle>2*Math.PI) {p.angle-=2*Math.PI;}
}
System.out.println(p1.name+".angle="+p1.angle);
System.out.println(p1.name+".speed="+p1.speed);
}
function line (p1:Particle, p2:Particle,ang:Number){
var k=0;
if (ang<Math.PI) {ang=2*Math.PI-ang;k++;}
if (ang==0) {ang=Math.PI;}
var dopang;
if (p1.angle!=0) dopang=p1.angle
else dopang=p2.angle;
var v1:Number;
var v2:Number;
System.out.println("ang="+ang);
v=(p1.speed+p2.speed)/(1+p1.speed*p2.speed);
System.out.println("v="+v);
v1=p2.mass*Math.sinh(arth(v))/(p1.mass+p2.mass*Math.cosh(arth(v)));
System.out.println("v1="+v1);
v2=p1.mass*Math.sinh(arth(v))/(p2.mass+p1.mass*Math.cosh(arth(v)));
System.out.println("v2="+v2);
p1.angle=-tch1(v2, tch(ang-Math.PI, v1,v2),v1)-dopang;//угол отлета первой частицы
System.out.println("p1.angle="+p1.angle);
p2.angle=tch1(v2,tch(ang,v2,v2),v2)-dopang;//угол отлета второй частицы
System.out.println("p2.angle="+p2.angle);
p1.speed=tch(Math.PI-ang,v1,v2);
System.out.println("p1.speed="+p1.speed);
p2.speed=tch(ang,v2,v2);
System.out.println("p2.speed="+p2.speed);
if (k!=0){
p1.angle=-p1.angle;
p2.angle=-p2.angle;
k--;
}
for (p in [p1, p2]){
if (p.angle<0) {p.angle+=2*Math.PI;}
if (p.angle>2*Math.PI) {p.angle-=2*Math.PI;}
}
}
function line_for_foton (p1:Particle, p2:Particle, ang:Number){
if (p1.speed==1){
if (not(p2.speed==1)) p1.angle=Math.random()*Math.PI*2
}
else p2.angle=Math.random()*Math.PI*2
}
function start (p1:Particle,p2:Particle, ang:Number){
var angle=p2.angle+Math.PI;
var speed=p2.speed;
if (angle<0) angle+=2*Math.PI;
System.out.println(p2.angle);
System.out.println(p1.dX);
sub(p1,p2.angle, p2.speed);
sub(p2,p2.angle, p2.speed);
if (p1.speed==1 or p2.speed==1){
line_for_foton (p1,p2,ang);
} else {
line(p1,p2, ang);
}
sub(p1,angle, speed);
sub(p2,angle, speed);
}
public class Particle{//класс частиц
public attribute name:String ;
public attribute speed:Number on replace {if (speed==0) angle=0};
public attribute startspeed:Number;
public attribute color:Color;
public attribute x:Number ;
public attribute y:Number ;
public attribute dX=bind Math.cos(angle)*speed*10/sp ;
public attribute startx:Number on replace{ x = startx; };
public attribute starty:Number on replace{ y = starty; };
public attribute radius:Number ;
public attribute mass:Number on replace {if (mass==0) speed=1};
public attribute dY=bind Math.sin(angle)*speed*10/sp;
public attribute angle:Number;
public attribute startangle:Number;
public attribute flag=0;
public attribute flag2=0;
public function compare(p:Particle, eps:Number):Boolean{
return (p.speed == 0.0 and speed == 0.0) or ( abs(p.angle - angle) < eps and abs(p.speed - speed) < eps );
}
public function toString():String{
var res = "Particle\{\n";
res += "name: {name}\n";
res += "angle: {angle}\n";
res += "speed: {speed}\n";
res += "}";
return res;
}
}
class TestCase{
public attribute eps:Number = 0.1;
public attribute angle: Number;
public attribute particle1: Particle;
public attribute particle2: Particle;
public attribute result1: Particle;
public attribute result2: Particle;
public function print(p: Particle, res:Particle){
System.out.println("=========== Particles are not equal =============");
System.out.println("particle: {p}");
System.out.println("result: {res}");
}
public function compare(){
if(not result1.compare(particle1, eps)){
print(particle1, result1);
}
if(not result2.compare(particle2, eps)){
print(particle2, result2);
}
}
}
public class ParticleSystem extends CustomNode{//сама модель
public attribute particles: Particle[];
public attribute dt:Number = 0.05 ;
public function run () {
for (particle in particles){
sp = Math.max(sp,particle.speed);
if (particle.flag2==0){
particle.flag2++;
particle.startangle=particle.angle;
particle.startspeed=particle.speed;
particle.startx=particle.x;
particle.starty=particle.y;
}
}
for (particle1 in particles){
for (particle2 in particles[
particle| particle != particle1]){
var minDistance = particle1.radius + particle2.radius;
if( Math.sqrt(q(particle1.x - particle2.x)+q(particle1.y - particle2.y)) < minDistance and particle1.flag==0 and particle2.flag==0){//столкновение
particle1.flag=1;
particle2.flag=1;
System.out.println("Particle collision!");
start(particle1, particle2, Math.PI/2);
/*for(test in tests){
test.particle1=particle1;
test.particle2=particle2;
start(test.particle1, test.particle2, test.angle);
test.compare();} */
}
if ( Math.sqrt(q(particle1.x - particle2.x)+q(particle1.y - particle2.y)) > minDistance and ((particle1.flag==1) or (particle2.flag==1))){
particle1.flag=0;
particle2.flag=0;
}
}
}
for (particle in particles){//движение
if (particle.angle<0) {particle.angle+=2*Math.PI;}
if (particle.angle>=2*Math.PI) {particle.angle-=2*Math.PI;}
particle.x = particle.dX * dt *r + particle.x;
particle.y = particle.dY * dt *r + particle.y;
for (particle1 in particles){ //торможение
for (particle2 in particles){
if (Math.sqrt(particle1.x*particle1.x+particle1.y*particle1.y)>150 or (
Math.sqrt(particle2.x*particle2.x+particle2.y*particle2.y)>150))
{
particle1.speed=0;
particle2.speed=0;
}
}
}
}
}
function create():Node{
return Group{
content:bind [ for (particle in particles){
Circle{
radius: particle.radius
fill: bind particle.color
centerX: bind particle.x
centerY: bind particle.y
onMouseDragged: function( e: MouseEvent ){
particle.startx = e.getX();
particle.x=e.getX();
particle.starty = e.getY();
particle.y = e.getY();
}
}
}
]
}
}
}
public class SetupParticleSystem extends CustomNode{
public attribute particles:Particle[];
attribute index:Integer on replace{
mass = "{particles[index].mass}";
speed = "{particles[index].speed}";
x = "{particles[index].x}";
y = "{particles[index].y}";
angle = "{particles[index].angle}";
};
attribute mass:String on replace{
particles [index].mass = java.lang.Double.parseDouble(mass);
};
attribute speed:String on replace{
particles [index].speed = java.lang.Double.parseDouble(speed);
particles [index].startspeed = java.lang.Double.parseDouble(speed);
};
attribute x:String on replace{
particles [index].x = java.lang.Double.parseDouble(x);
};
attribute angle:String on replace{
particles [index].angle = java.lang.Double.parseDouble(angle);
particles [index].startangle = java.lang.Double.parseDouble(angle);
};
attribute y:String on replace{
particles [index].y = java.lang.Double.parseDouble(y);
};
function create():Node{
return ComponentView {
component: BorderPanel{
left: List{
items: bind
for (particle in particles)
ListItem{
text: particle.name
}
selectedIndex: bind index with inverse
}
center: FlowPanel{ content: GridPanel{
columns: 3, rows: 5
content: [
Label{ text: "Mass"},
TextField{ columns: 7, text: bind mass with inverse},
Label {},
Label{ text: "Speed"},
TextField{ columns: 7, text: bind speed with inverse},
Label{ text: bind "{%+10.4f particles[index].speed}"},
Label{ text: "Coordinate x"},
TextField{ columns: 7, text: bind x with inverse},
Label{ text: bind "{%+10.4f particles[index].x}"},
Label{ text: "Coordinate y"},
TextField{ columns: 7, text: bind y with inverse},
Label{ text: bind "{%+10.4f particles[index].y}"},
Label{ text: "Angle"},
TextField{ columns: 7, text: bind angle with inverse},
Label{ text: bind "{%+10.4f particles[index].angle}"},
]
} }
right: FlowPanel{ content: GridPanel{
rows: 3
content:[
Button{
text: bind if(r==1) then "Pause" else "Run"
action: function(){timeline.start();
r=1-r;}
},
Button{
text: "Reset"
action:function(){
for (particle in particles){
particle.x=particle.startx;
particle.y=particle.starty;
particle.speed=particle.startspeed;
particle.angle=particle.startangle;
particle.flag=0;
particle.flag2=0;
}}
},
Button{
text: "Add"
action:function(){l++; insert Particle{
name: "Particle "+l
startx: (Math.random()-0.5)*200
starty: (Math.random()-0.5)*200
radius: 4
mass: 10
color: Color.rgb(Math.random()*255, Math.random()*255, Math.random()*255)
} into particles;
} }]
}
}}
}
}
}
import javafx.scene.*;
import javafx.scene.paint.*;
import javafx.scene.text.*;
import javafx.scene.geometry.*;
import javafx.scene.transform.*;
import javafx.scene.image.ImageView;
import javafx.scene.image.Image;
import javafx.input.MouseEvent;
function angle(x1:Number, y1:Number, x2:Number, y2:Number):Number{
var scalar = x1 * x2 + y1 * y2;
var length1 = Math.sqrt(x1 * x1 + y1 * y1);
var length2 = Math.sqrt(x2 * x2 + y2 * y2);
return Math.acos( scalar / ( length1 * length2));
}
function speedpt(ang1:Number, ang2:Number):Number{
var a = Math.sin(ang1)/Math.sin(ang1+ang2);
var b = Math.sin(ang2)/Math.sin(ang1+ang2);
var c = q(q(b)-q(a))+1-(q(a)+q(b))*2;
var p = (-q(q(b)-q(a))+1)*2;
var z = q(q(a)-q(b))-3+(q(b)+q(a))*2;
var x = (-p-Math.sqrt(q(p)-c*z*4))/(c*2);
return Math.sqrt(1-1/q(x))
}
class RotatedLine extends CustomNode{
public attribute color:Color;
public attribute name:String;
public attribute reflect:Boolean;
public attribute centerX:Number;
public attribute centerY:Number;
public attribute startX:Number;
public attribute startY:Number;
public function create(){
Group{
content:[
Line{
startX: bind centerX
startY: bind centerY
endX: bind centerX + startX
endY: bind centerY + startY
},
Circle{
centerX: bind centerX + startX
centerY: bind centerY + startY
radius: 5
fill: bind color
onMouseDragged: function( e: MouseEvent ):Void {
startX = e.getX() - centerX;
startY = e.getY() - centerY;
}
},Text{
x: bind centerX + startX + 5
y: bind centerY + startY - 5
fill: Color.RED
font: Font { size: 16 style: FontStyle.PLAIN }
content: name
},
if (reflect)
Line{
startX: bind centerX
startY: bind centerY
endX: bind centerX - startX
endY: bind centerY - startY
strokeDashArray: [ 10.0 ]
} else []
]
}
}
}
class ParticleImage extends CustomNode{
public attribute url: String;
public attribute color:Color = Color.CORAL;
public attribute lineColor:Color = Color.CORAL;
public attribute scale:Number = 1.0;
public attribute angle1:Number = bind angle(-startX, -startY, endX1, endY1);
public attribute angle2:Number = bind angle(-startX, -startY, endX2, endY2);
public attribute speed:Number = bind speedpt(angle1,angle2);
public attribute disangle:Number = bind 2*Math.atan(Math.sqrt(Math.tan(angle1)/Math.tan(angle2)));
attribute centerX:Number = 50;
attribute centerY:Number = 50;
attribute startX:Number = -140;
attribute startY:Number = 0;
attribute endX1:Number = 90;
attribute endY1:Number = -90;
attribute endX2:Number = 90;
attribute endY2:Number = 90;
public function create(){
Group{
transform: Scale{ x: bind scale y: bind scale}
onMouseWheelMoved: function( e: MouseEvent ){
var s = -e.getWheelRotation();
scale += s / 10;
}
content:[
ImageView {
image: bind Image {
url: url
}
},
Circle{
centerX: bind centerX
centerY: bind centerY
radius: 20
opacity: 0.01
fill: Color.WHITE
onMouseDragged: function( e: MouseEvent ){
centerX = e.getX();
centerY = e.getY();
}
},
Circle{
centerX: bind centerX
centerY: bind centerY
radius: 20
stroke: bind color
},
Circle{
centerX: bind centerX
centerY: bind centerY
radius: 120
stroke: bind color
},
RotatedLine{
name: "0"
reflect: true
centerX: bind centerX
centerY: bind centerY
startX: bind startX with inverse
startY: bind startY with inverse
color: lineColor
},
RotatedLine{
name: "1"
centerX: bind centerX
centerY: bind centerY
startX: bind endX1 with inverse
startY: bind endY1 with inverse
color: lineColor
},
RotatedLine{
name: "2"
centerX: bind centerX
centerY: bind centerY
startX: bind endX2 with inverse
startY: bind endY2 with inverse
color: lineColor
},
Text{
x: 10
y: 50
fill: lineColor
content: bind "Angle 1: {%10.5f angle1}"
},
Text{
x: 10
y: 80
fill: lineColor
content: bind "Angle 2: {%10.5f angle2}"
},
Text{
x:10
y:110
fill: lineColor
content: bind "Speed: {%10.5f speed}"
},
Text{
x: 10
y: 140
fill: lineColor
content: bind "DispAngle: {%10.5f disangle}"
}
]
}
}
}
class ImageItem{
attribute name:String;
attribute path:String;
}
var images = [ImageItem{ name: "Empty"}, ImageItem{ name: "Protons" path: "protons.png"}];
var imageIndex = 1;
Frame{
title: "Particle Collision"
width: 800
height: 600
closeAction: function(){
System.exit(0);
}
stage: Stage{
content: [
Group{
content: bind [
ComponentView{
translateX: 460
translateY: 140
component: ComboBox {
items: for (image in images)
ComboBoxItem {
text: image.name
selected: true
}
selectedIndex: bind imageIndex with inverse
}
}, if(0 < imageIndex )
ParticleImage{
translateY: 170
centerX: 200
centerY: 200
url: bind "{__DIR__}{images[imageIndex].path}"
color: Color.GREEN
}
else []
]
},
SetupParticleSystem{ particles:bind particleSystem.particles with inverse},
particleSystem
]
}
visible: true
}
Тестирование функции столкновения частиц[]
Закон сохранения 4х импульса сталкивающихся частиц[]
1. , угол разлета в системе центра масс равен
Выразим из этих 2х уравнений угол через скорость :
Составим табличку для некоторых скоростей:
0.3 | 0.5 | 0.7 | |
---|---|---|---|
0.779 | 0.766 | 0.7398 |
Расчет скорости налетающей частицы[]
Дано: углы разлета частиц в лабораторной системе отсчета.
Надо найти скорость налетающей частицы.
(I) (II) (III)
Вспомогательные формулы:
=> =>
(II) => (I) => =>
тогда:
=>
аналогично:
Обозначим:
тогда:
(III) =>
Рассмотрим выражение:
Возводим его в квадрат:
Еще раз возводим в квадрат:
Тогда
Теперь подставляем k, n и m:
Делим на :
В итоге получаем квадратное уровнение отностительно x. Собираем коэффициенты при , и , решаем квадратное уровнение и находим x.
Тогда:
Расчет скорости налетающей частицы (Версия 2)[]
Напишем закон сохранения взяв проекции на оси:
Т.к. массы частиц одинаковы, получаем из второго равенства, что углы отлета частиц равны, тогда:
Пользуясь формулой , выражаем квадрат синуса через косинус во втором равенстве, подставляем первое:
Решаем как квадратичное уравнение относительно переменной , и получаем:
А затем по формуле , находим значение скорости.
Фотоснимки столкновения частиц[]