download and run this
https://drive.google.com/file/d/1_IPdpTKzLNTJYxBxxbtJyAkH3dnFwSZD/view?usp=sharing
//or....stand alone / ready to compile and run simple code
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package j2ballscollisionfounder;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
/**
*
* @author dimitrak
*/
public class J2BallsCollisionFounder extends JFrame implements MouseListener,MouseMotionListener,MouseWheelListener{
public static void main(String[] args) {
new J2BallsCollisionFounder();
}
Balla a=new Balla();
Balla b=new Balla();
Thread thrSim=new Thread(){
public void run(){
while(true){
runSimStep();
}
}
};
JLabel jlDt=new JLabel("DT-sim millis");
JSpinner jspDt=new JSpinner(new SpinnerNumberModel(100,10,1000,10));
JPanel jpDt=new JPanel(new BorderLayout());
JPanel jpn=new JPanel(new FlowLayout());
public J2BallsCollisionFounder(){
super("Found TIME of Collision between 2 balls with (radius,speed,angle)");
b.col=Color.black;
jpDt.add(BorderLayout.WEST,jlDt);
jpDt.add(BorderLayout.CENTER,jspDt);
jpn.add(jbPlay);
jpn.add(jbTimeZero);
jpn.add(jpDt);
getContentPane().add(BorderLayout.CENTER,jp);
getContentPane().add(BorderLayout.NORTH,jpn);
setBounds(0,0,777,666);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
jp.addMouseListener(this);
jp.addMouseMotionListener(this);
jp.addMouseWheelListener(this);
thrSim.start();
jbPlay.addActionListener(e->jbPlay());
jbTimeZero.addActionListener(e->jbTimeZero());
a.resetAtPos(300,100);
a.resetAtAngle(Math.PI/2);
a.resetAtSpeed(60);
b.resetAtPos(100,300);
b.resetAtAngle(-Math.PI/8);
b.resetAtSpeed(60);
recomputeCollisionTime();
}
Graphics2D g=null;
JPanel jp=new JPanel(){
public void paintComponent(Graphics gr){
super.paintComponent(gr);
g=(Graphics2D)gr;
paintingBalls();
}
};
Font font=new Font("Dialog",0,16);
void paintingBalls(){
g.setColor(Color.black);
g.setFont(font);
int x=10;
int y=font.getSize();
g.drawString("Press IN some ball and dragg mouse to change ball location", x,y);
y+=font.getSize();
g.drawString("Mouse Roll to change ball Speed", x,y);
y+=font.getSize();
g.drawString("Mouse Roll +SHIFT to change ball Angle", x,y);
a.paint(g);
b.paint(g);
}
@Override
public void mouseClicked(MouseEvent e) {
}
boolean pressedLeft,pressedRight;
Balla ballNowPressed=a;
@Override
public void mousePressed(MouseEvent e) {
pressedLeft=e.getButton()==MouseEvent.BUTTON1;
pressedRight=e.getButton()==MouseEvent.BUTTON3;
ballNowPressed=null;
double dist1=a.dist(e.getX(),e.getY());
double dist2=b.dist(e.getX(),e.getY());
System.out.println(""+dist1+" , "+dist2);
if(dist1<=a.r && dist1<=dist2){
ballNowPressed=a;
}
if(dist2<=b.r && dist2<=dist1){
ballNowPressed=b;
}
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void mouseDragged(MouseEvent e) {
if(ballNowPressed!=null){
ballNowPressed.resetAtPos(e.getX(),e.getY());
recomputeCollisionTime();
}
}
@Override
public void mouseMoved(MouseEvent e) {
}
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if(ballNowPressed!=null){
if(!e.isShiftDown()){
ballNowPressed.resetAtSpeedDif(-5*e.getWheelRotation());
}
else{
ballNowPressed.resetAtAngleDif(Math.toRadians(-5*e.getWheelRotation()));
}
recomputeCollisionTime();
}
}
/**
* Searching t (collision time)
* AendX=AstartX+(t*Aspeed)cos(Aangle)
* AendY=AstartY+(t*Aspeed)sin(Aangle)
* BendX=BstartX+(t*Bspeed)cos(Bangle)
* BendY=BstartY+(t*Bspeed)sin(Bangle)
*
* (BendY-AendY)^2 +(BendX-AendX)^2 = (ARadius+BRadius)^2
*/
void recomputeCollisionTime(){
//System.out.println("recomputing collision time");
double tLess=-1;
double aco=a.sp*Math.cos(a.an);
double asi=a.sp*Math.sin(a.an);
double bco=b.sp*Math.cos(b.an);
double bsi=b.sp*Math.sin(b.an);
double dsi=bsi-asi;
double dco=bco-aco;
double dy=b.yf-a.yf;
double dx=b.xf-a.xf;
double A=dsi*dsi+dco*dco;
double B=2*((dsi)*(dy)+(dco)*(dx));
double C=dy*dy+dx*dx-Math.pow(a.r+b.r,2);
double D=B*B-4*A*C;//System.out.println("D = "+D);
if(D<0){System.out.println("No solutions");}
else{
double t1=(-B-Math.sqrt(D))/(2*A);
double t2=(-B+Math.sqrt(D))/(2*A);//System.out.println("t1 : "+t1+" , t2: "+t2);
tLess=t1;
if(t2<t1){tLess=t2;}
}
a.resetAtTimeCollision(tLess*1000);
b.resetAtTimeCollision(tLess*1000);
jp.repaint();
}
JButton jbPlay=new JButton("Play");
JButton jbTimeZero=new JButton("TimeZero");
boolean simPaused=true;
long stepMillis=100;
long pauseMillis=60000;
double simTime=0;
double simDtime(){return (int)jspDt.getValue();}
double simMaxtime=5000;
void runSimStep(){
long sl=pauseMillis;
if(!simPaused){
boolean simend=false;
sl=stepMillis;
simTime+=simDtime();
if(simTime>simMaxtime){
simTime=simMaxtime;
simend=true;
}
a.resetAtTimeNow(simTime);
b.resetAtTimeNow(simTime);
jp.repaint();
if(simend){
simPause();
simTime=0;
}
}
try{thrSim.sleep(sl);}catch(InterruptedException inter){}
}
void jbPlay(){
if(simPaused){
simUnPause();
}
else{
simPause();
}
}
void simPause(){
jbPlay.setText("Play");
simPaused=true;
}
void simUnPause(){
jbPlay.setText("Simulating");
simPaused=false;
thrSim.interrupt();
}
void jbTimeZero(){
simTime=0;
}
}
class Balla{
Color col=Color.BLUE;
double r=50;
double d=2*r;
double xf=2*r+Math.random()*300,yf=2*r+Math.random()*300;
double an=Math.toRadians(Math.random()*360);
double sp=10+Math.random()*100;
double xl,yl;
double timeEnd=5000;
double xe,ye;
double timeNow=timeEnd/2;
double xn,yn;
double timeCollision=-1;
double xc,yc;
public Balla(){
resetAtPos();
}
void resetAtPos(){
resetAtPos(xf, yf);
}
void resetAtPos(double x,double y){
xf=x;
yf=y;
xl=xf+r*Math.cos(an);
yl=yf+r*Math.sin(an);
//1000 millis sp
//timeEnd x?
double distMaxTime=(sp*timeEnd)/1000;
xe=xf+distMaxTime*Math.cos(an);
ye=yf+distMaxTime*Math.sin(an);
double distNowTime=(sp*timeNow)/1000;
xn=xf+distNowTime*Math.cos(an);
yn=yf+distNowTime*Math.sin(an);
if(timeCollision>0){
double distAtCollision=(sp*timeCollision)/1000;
xc=xf+distAtCollision*Math.cos(an);
yc=yf+distAtCollision*Math.sin(an);
}
}
void resetAtAngle(double newAngle){
an=newAngle;
resetAtPos();
}
void resetAtAngleDif(double difAngle){
resetAtAngle(difAngle+an);
}
void resetAtSpeed(double newSpeed){
sp=newSpeed;
resetAtPos();
}
void resetAtSpeedDif(double difSpeed){
resetAtSpeed(difSpeed+sp);
}
void resetAtTimeNow(double newNowTime){
timeNow=newNowTime;
resetAtPos();
}
void resetAtTimeCollision(double newCollisionTime){
timeCollision=newCollisionTime;
resetAtPos();
}
public double dist(double x,double y){
return Point.distance(xf, yf, x, y);
}
static BasicStroke strokeNormal=new BasicStroke(1);
static BasicStroke strokeMoving=new BasicStroke(1,0,0,10,new float[]{10,10},0);
public void paint(Graphics2D g){
g.setStroke(strokeNormal);
g.setColor(col);
g.drawOval((int)(xf-r),(int)(yf-r), (int)(d),(int)( d));
g.drawLine((int)(xf),(int)(yf),(int)(xl),(int)(yl));
g.drawOval((int)(xe-r),(int)(ye-r), (int)(d),(int)( d));
double spn=sp*1000;
spn=(long)spn;
spn/=1000;
g.drawString("V="+(spn)+" px/s", (int)(xf),(int)(yf));
g.setStroke(strokeMoving);
g.drawOval((int)(xn-r),(int)(yn-r), (int)(d),(int)( d));
if(timeCollision>0){
g.setColor(Color.RED);
g.setStroke(strokeNormal);
int ucx=(int)(xc-r);
int ucy=(int)(yc-r);
g.drawOval(ucx,ucy, (int)(d),(int)( d));
//g.drawLine(ucx,ucy,(int)(ucx+d),(int)(ucy+d));
}
}
}
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου