ФЭНДОМ


Главная | Описание языка | FXD | API | Примеры | Инструменты Разработки | Новости | Ресурсы | Форум

Разлет частиц Править

Релятивистский случай Править

Particle collision

Triangle

Теорема косинусов в геометрии Лобачевского:

  ch \ a = ch \ b * ch \ c - sh \ b * sh \ c * cos \ \alpha 

Вторая теорема косинусов:

  cos \ \alpha = - cos \ \beta * cos \ \gamma + sin \ \beta * sin \ \gamma * ch \ a 

SpeedMap

Столкновение частиц. Расчеты проводятся на карте скоростей процесса. Таким образм, если v1 отвечает длине вектора скорости на карте в системе центра масс, то выполнены следущие равенства:

 \vec p = m * sh \ \vec v1 , импульс частицы,
 E = m * ch \ v1 , энергия,
 v=th \ v1 , скорость часицы, относительно скорости света.
 

Закон сохранения импульса и энергии:

  \vec p_1  + \vec p_2  = \vec p_1 \prime  + \vec p_2 \prime  
  E_1  + E_2  = E_1 \prime  +  E_2 \prime  

Из этих законов можно заметить, что v1=v1' и v2=v2'.

Релятивистская формула сложения скоростей:

  AB = \frac {v1 + v2} {1 + v1 * v2 / c^2} , где с - скорость света.

В лабораторной системе отсчета известна только скорость налетающей частицы-AB, с помощью масс можно найти скорости v1 и v2, для этого будем использовать 3 формулы: если AO обозначить за a, OB за b, а AB за c (c=a+b), то v1=th\ a, v2=th\ b, и в системе центра масс импульс системы равен 0, т.е. модули импульсов равны, откуда

 p1=p2=>m1*sh\ a=m2*sh\ b  (релятивисткое правило рычага), т.е.   sh\ b=m1/m2*sh\ a 

Далее рассмотрим формулы синуса и косинуса суммы в гиперболической тригонометрии:

 sh\ c=sh (a+b)=sh\ a * ch\ b +sh\ b * ch\ a, 
 ch\ c=ch\ a* ch\ b + sh\ a * sh\ b, 

выразим из второй формулы ch b:

 ch\ b=\frac {ch c - sh a * sh b} {ch a}, 

подставляем это выражение в первую формулу, заменяем sh b по правилу рычага:

 sh c=sh a * ch b + sh b * ch a=\frac {sh a} {ch a} * (ch c - \frac {m1} {m2} *sh^2 a) +\frac {m1} {m2} * sh\ a * ch a 
 m2 * sh\ c=th\ a * m2 * ch\ c + m1 * sh\ a * (ch\ a - \frac {sh^2\ a} {ch\ a}) 
 m2 * sh\ a=th\ a * m2 * ch\ c + m1 * th\ a 
 v1 = th\ a = \frac {m2 * sh\ c} {m1 + m2 * ch\ c} 

Аналогично  v2 = \frac {m1 * sh\ c} {m2 + m1 * ch\ c}.

Далее, по теореме косинусов можно найти скорости отлета c и c' и углы при них в лабораторной системе отсчета  \alpha и  \beta :

 c = ch^2\ v2 - sh^2\ v2 * cos\ (\pi - \phi)

 c' = ch\ v1 * ch\ v2 - sh\ v1 * sh\ v2 * cos\ \phi

 cos\ \alpha = \frac {ch\ c * ch\ v2 - ch\ v2} {sh\ c * sh\ v2}

 cos\ \beta = \frac {ch\ c' * ch\ v2 - ch\ v1} {sh\ c * sh\ v2}

Отсюда получаем скорость в координатной системе: Vx=c * cos \ \alpha Vy=c * sin\ (arccos\ \alpha)

Полная программа:


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();
}

Определение угла разлета частиц на фотоснимке Править

Фотоснимок сталкивающихся протонов:

AngleDetection 1


Увеличение фотоснимка и определение углов разлета частиц:

AngleDetection 2


Программа:

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х импульса сталкивающихся частиц Править

 \vec P = m \vec v / \sqrt{1-v^2} 
 E = m / \sqrt{1-v^2} 

Particles four impulse

 m_1 v / \sqrt{1-v^2} = m_1 v_1 \cos \alpha / \sqrt{1-v_1^2}  + m_2 v_2 \cos \beta / \sqrt{1-v_2^2}
 m_1 v_1 \sin \alpha / \sqrt{1-v_1^2}  = m_2 v_2 \sin \beta / \sqrt{1-v_2^2}
 m_1 / \sqrt{1-v^2} + m_2 = m_1 / \sqrt{1-v_1^2}  + m_2 / \sqrt{1-v_2^2}


1. m_1=m_2, угол разлета в системе центра масс равен \pi

  u = v_1 = v_2 
 v / \sqrt{1-v^2} = 2 u \cos \alpha / \sqrt{1-u^2} 
  1 / \sqrt{1-v^2} + 1 = 2 / \sqrt{1-u^2} 

Выразим из этих 2х уравнений угол \alpha через скорость v:

 cos \alpha = v / \sqrt{ 3 v^2 + 2 \sqrt{1 - v^2} - 2}

Составим табличку для некоторых скоростей:

v 0.3 0.5 0.7
\alpha 0.779 0.766 0.7398

Расчет скорости налетающей частицы Править

Particles four impulse

 m_1 v / \sqrt{1-v^2} = m_1 v_1 \cos \alpha / \sqrt{1-v_1^2}  + m_2 v_2 \cos \beta / \sqrt{1-v_2^2}
 m_1 v_1 \sin \alpha / \sqrt{1-v_1^2}  = m_2 v_2 \sin \beta / \sqrt{1-v_2^2}
 m_1 / \sqrt{1-v^2} + m_2 = m_1 / \sqrt{1-v_1^2}  + m_2 / \sqrt{1-v_2^2}


Дано: углы разлета частиц в лабораторной системе отсчета.

Надо найти скорость налетающей частицы.


 (I) m_1 v / \sqrt{1-v^2} = m_1 v_1 \cos \alpha / \sqrt{1-v_1^2}  + m_2 v_2 \cos \beta / \sqrt{1-v_2^2}
 (II) m_1 v_1 \sin \alpha / \sqrt{1-v_1^2}  = m_2 v_2 \sin \beta / \sqrt{1-v_2^2}
 (III) m_1 / \sqrt{1-v^2} + m_2 = m_1 / \sqrt{1-v_1^2}  + m_2 / \sqrt{1-v_2^2}

Вспомогательные формулы:

  \frac {w}  {\sqrt{1-w^2}} = \gamma   =>  \frac {1}  {\sqrt{1-w^2}}=  \sqrt{1+\gamma^2}    
  \frac {1}  {\sqrt{1-w^2}} = \delta   =>  \frac {w}  {\sqrt{1-w^2}}=  \sqrt{\delta^2-1}  


 (II) => \frac {v_1} {\sqrt{1-v_1^2}} = \frac {v_2} {\sqrt{1-v_2^2}} \frac {\sin \beta } {\sin \alpha} \frac {m_2} {m_1} 
 (I) => \frac {v} {\sqrt{1-v^2}} = \frac {v_2} {\sqrt{1-v_2^2}}( \frac {\sin \beta } {\sin \alpha} \cos \alpha  + \cos \beta) \frac {m_2} {m_1} => 
 \frac {v} {\sqrt{1-v^2}} = \frac {m_2} {m_1} \frac {v_2} {\sqrt{1-v_2^2}} \frac {\sin ( \alpha + \beta ) } {\sin \alpha}     

тогда:

 \frac {v_2} {\sqrt{1-v_2^2}} = \frac {m_1} {m_2} \frac {v} {\sqrt{1-v^2}} \frac {\sin \alpha} {\sin ( \alpha + \beta ) }      =>

аналогично:

 \frac {v_1} {\sqrt{1-v_1^2}} = \frac {v} {\sqrt{1-v^2}} \frac {\sin \beta} {\sin ( \alpha + \beta ) }  


Обозначим:

x = \frac {1} {\sqrt{1-v^2}}
a = \frac {m_1} {m_2} \frac {\sin \alpha} {\sin ( \alpha + \beta ) }
b = \frac {\sin \beta} {\sin ( \alpha + \beta ) }


тогда:

 \frac {v_2} {\sqrt{1-v_2^2}} = a \sqrt{x^2-1}   
 \frac {v_1} {\sqrt{1-v_1^2}} = b \sqrt{x^2-1}   

(III) =>

 x + 1 = \sqrt{1+ a^2 (x^2-1)} + \sqrt{1+ b^2 (x^2-1)} 

Рассмотрим выражение:

 k = \sqrt{n} + \sqrt{m} 

Возводим его в квадрат:

 k^2 =  n + m + 2 \sqrt{n} \sqrt{m} 

Еще раз возводим в квадрат:

 (k^2 -(n + m)) ^2 = 4 n m 

Тогда

 k^4 - 2 k^2 (n + m) + (n + m) ^2 = 4 n m 
 k^4 - 2 k^2 (n + m) + (n - m) ^2 = 0 


Теперь подставляем k, n и m:

 (x + 1)^4 - 2 (x + 1)^2 (2 + ( a^2 + b^2 ) (x^2-1)) + ((b^2 - a^2)(x^2-1)) ^2 = 0 

Делим на ((x + 1)^2:

 (x + 1)^2 - 2 (2 + ( a^2 + b^2 ) (x^2-1)) + ((b^2 - a^2)(x-1)) ^2 = 0 

В итоге получаем квадратное уровнение отностительно x. Собираем коэффициенты при x ^2, x ^1 и x ^0, решаем квадратное уровнение и находим x.

Тогда:

 v = \sqrt{ 1 - \frac{1}{x^2}}

Расчет скорости налетающей частицы (Версия 2) Править

Напишем закон сохранения взяв проекции на оси:

m*sh\ a = m*sh\ a1 * cos\ \alpha + m*sh\ a2 * cos\ \beta

m*sh\ a1 * sin\ \alpha = m*sh\ a2 * sin\ \beta

m*ch\ a + m = m * ch\ a1 + m*ch\ a2


Т.к. массы частиц одинаковы, получаем из второго равенства, что углы отлета частиц равны, тогда: ch\ a + 1 = 2*ch\ a1  =>  ch\ a1 = \frac {ch\ a + 1} {2}

sh\ a = 2*sh\ a1*cos\ \alpha  =>  sh^2\ a =4*sh^2\ a1* cos^2\ \alpha

Пользуясь формулой ch^2\ a - sh^2\ a = 1, выражаем квадрат синуса через косинус во втором равенстве, подставляем первое: ch^2\ a - 1 = 4 * (ch^2\ a1 - 1) * cos\ \alpha

ch^2\ a - 1 = 4 * (\frac {(ch\ a1 + 1)^2} {4} -1)* cos\ \alpha

ch^2\ a - 1 = cos\ \alpha * (ch^2\ a + 2 * ch\ a +1 - 4)

ch^2\ a - 1 = cos\ \alpha * (ch^2\ a + 2 * ch\ a -3)


Решаем как квадратичное уравнение относительно переменной ch\ a , и получаем: ch\ a = \frac {3* cos^2\ \alpha - 1} {sin^2\ \alpha}


А затем по формуле th\ a = \sqrt {1 - \frac {1} {ch^2\ a}}, находим значение скорости.

Фотоснимки столкновения частиц Править

Столкновение протонов 1

Protons1


Столкновение протонов 2

Protons2


Ссылки Править

Столкновение протонов
Теги для математических формул

Обнаружено использование расширения AdBlock.


Викия — это свободный ресурс, который существует и развивается за счёт рекламы. Для блокирующих рекламу пользователей мы предоставляем модифицированную версию сайта.

Викия не будет доступна для последующих модификаций. Если вы желаете продолжать работать со страницей, то, пожалуйста, отключите расширение для блокировки рекламы.

Также на ФЭНДОМЕ

Случайная вики