Κυριακή 5 Φεβρουαρίου 2023

Collision Time For Two Balls

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

        }

    }

}

Δεν υπάρχουν σχόλια: