Java图像沿列表中的点移动并使用线性插值 [英] Java image move along points in list and use linear interpolation

查看:124
本文介绍了Java图像沿列表中的点移动并使用线性插值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让图像沿路径行进。该路径的点存储在ArrayList中。现在图像每两秒跳到下一个点,所以我必须使用线性插值来使运动平滑。但是如何在update()方法中使用线性插值?我在网上搜索了这个问题,但在更新方法中找不到关于线性插值的更多信息,结合带有点的ArrayList。



更新方法

  public void update(){

repaint();
if(counter< Lane.firstLane.size()){

startPoint = new Point(carPosition.x,carPosition.y);
endPoint = new Point(Lane.firstLane.get(counter).x,Lane.firstLane.get(counter).y);
pointOnTimeLine = new Point(startPoint);
计时器计时器=新计时器(40,新ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
if(startTime == null){
startTime = System.currentTimeMillis();
}
long now = System.currentTimeMillis();
long diff = now - startTime;
if(diff> = playTime) {
diff = playTime;
((Timer)e.getSource())。stop();
}
double i =(double)diff /(double)playTime;
pointInTime = i;

//pointOnTimeLine.x =(int)(startPoint.x +((endPoint.x - startPoint.x)* i));
/ /pointOnTimeLine.y =(int)(startPoint.y +((endPoint.y - startPoint.y)* i));

//carPosition.setLocation(pointOnTimeLine);
carPosition .x =(int)lerp(sta rtPoint.x,endPoint.x,I);
carPosition.y =(int)lerp(startPoint.y,endPoint.y,i);

System.out.println(Car position:x+ carPosition.x +:y+ carPosition.y);
//System.out.println(\"Point\"+pointOnTimeLine);

repaint();
counter ++;
}
});
timer.start();

}
else {
//System.out.println(目的达到);
}


//carPosition.x+=1;
// repaint();


}


双倍lerp(双倍,双倍,双倍){
返回+(b - a) * t;
}

移动汽车的线程

  public void moveCar(){
Runnable helloRunnable = new Runnable(){
public void run(){

car .update();
repaint();


}
};

ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(helloRunnable,0,40,TimeUnit.MILLISECONDS);
}

Lane.cs

  public class Lane {

public static List< Point> firstLane = new ArrayList<>(Arrays.asList(new Point(10,135),new Point(124,190),new Point(363,190),new Point(469,210)));

}

编辑:我根据MadProgrammers更改了我的代码建议。动画现在在这里播放动画电影和 所以你必须原谅我不再重新发布代码。



现在,为了我的钱,我还​​花了一些时间来了解像时间框架和/或 Trident 和/或通用补间引擎


I'm trying to let an image follow a path. The points of this path are stored in an ArrayList. Right now the image jumps to the next point every two seconds, so I have to use linear interpolation to make the movement smooth. But how can I use linear interpolation in my update() method? I have a searched for this question on the net but couldn't find much information on linear interpolation in the update method in combination with an ArrayList with points.

Update method

public void update(){

    repaint();
    if(counter < Lane.firstLane.size()){

        startPoint = new Point(carPosition.x, carPosition.y);
        endPoint = new Point(Lane.firstLane.get(counter).x, Lane.firstLane.get(counter).y);
        pointOnTimeLine = new Point(startPoint);
        Timer timer = new Timer(40, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (startTime == null) {
                    startTime = System.currentTimeMillis();
                }
                long now = System.currentTimeMillis();
                long diff = now - startTime;
                if (diff >= playTime) {
                    diff = playTime;
                    ((Timer) e.getSource()).stop();
                }
                double i = (double) diff / (double) playTime;
                pointInTime = i;

                //pointOnTimeLine.x = (int) (startPoint.x + ((endPoint.x - startPoint.x) * i));
                //pointOnTimeLine.y = (int) (startPoint.y + ((endPoint.y - startPoint.y) * i));

                //carPosition.setLocation(pointOnTimeLine);
                carPosition.x=(int) lerp(startPoint.x,endPoint.x,i);                       
                carPosition.y=(int)lerp(startPoint.y,endPoint.y,i);

                System.out.println("Car position: x"+carPosition.x+": y"+carPosition.y );
                //System.out.println("Point"+pointOnTimeLine);

                repaint();
                counter++;
            }
        });
        timer.start();

     }
    else{
        //System.out.println("Destination reached");
    }


   //carPosition.x+=1;
   //repaint();    


}


double lerp(double a, double b, double t) {
    return a + (b - a) * t;
}

Thread to move the car

public void moveCar() {
    Runnable helloRunnable = new Runnable() {
        public void run() {

           car.update();
           repaint();


        }
    };

    ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    executor.scheduleAtFixedRate(helloRunnable, 0, 40, TimeUnit.MILLISECONDS);
}

Lane.cs

public class Lane {

     public static List<Point> firstLane = new ArrayList<>(Arrays.asList(new Point(10,135),new Point(124,190),new Point(363,190),new Point(469,210)));

}

EDIT: I have made changes to my code according to MadProgrammers suggestions. The animation works now here's the movie of the animation http://gyazo.com/e6a28b87cb905c0ff5eb023d68955321. My OP is updated with my current code. Next step is the turn part, but I think there is a more elegent way to call the car update method and repaint() in moveCar. I have specified the time in this thread to the same length as in the timer (40ms). Is there a better way to call car.update() and repaint in moveCar()?

解决方案

Let's break this down...

Basically you want to move from one point (A) to another (B) over a period of time (t). A given point between A and B at a given point in time is a percentage of the difference between the two (where t is normalized as a fraction between 0 and 1)

So, if A is 10 and B is 20 and t is 2 seconds, at 1 second p should be 15 (((B - A) * i) + A) where i is the normalized time difference of 0.5 (50% of 2 seconds = 1 second)

So, given any point in time, you can calculate the difference between the two points and calculate the position it should be at.

If you're wondering why I normalized the time, consider this, if you change t to be 4 seconds instead, the calculations don't change, we just need to calculate the normalized point in time (1 / 4 = 0.25) and run that back through the calculations to give us the desired result.

So, what you need to know is how long it will take to go from point A to point B. Then you need some mechanism which can regularly check the amount of time that has passed and calculate the current position of the object between the two points. For this you could use a Swing Timer to tick at a regular interval (like 40 milliseconds for example) until 2 seconds have elapsed.

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Long startTime;
        private long playTime = 2000;

        private Point startPoint, endPoint;
        private Point pointOnTimeLine;
        private double pointInTime; // For rendering...

        public TestPane() {
            startPoint = new Point(0, 95);
            endPoint = new Point(190, 95);
            pointOnTimeLine = new Point(startPoint);
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (startTime == null) {
                        startTime = System.currentTimeMillis();
                    }
                    long now = System.currentTimeMillis();
                    long diff = now - startTime;
                    if (diff >= playTime) {
                        diff = playTime;
                        ((Timer) e.getSource()).stop();
                    }
                    double i = (double) diff / (double) playTime;
                    pointInTime = i;

                    pointOnTimeLine.x = (int) (startPoint.x + ((endPoint.x - startPoint.x) * i));
                    pointOnTimeLine.y = (int) (startPoint.y + ((endPoint.y - startPoint.y) * i));

                    repaint();
                }
            });

            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            g2d.fill(new Ellipse2D.Double(startPoint.x, startPoint.y, 10, 10));
            g2d.fill(new Ellipse2D.Double(endPoint.x, endPoint.y, 10, 10));
            g2d.setColor(Color.GREEN);
            g2d.fill(new Ellipse2D.Double(pointOnTimeLine.x, pointOnTimeLine.y, 10, 10));
            g2d.dispose();
        }

    }

}

Okay, "but how does this help me?" I hear you asking. Well, the reality is, this is the basics for moving between multiple points.

In your code you have 4 key points in time, evenly distributed, over which the object must move, this means that each point is roughly 33% apart along the time line.

When you calculate the current position along the time line, you need to find the two points that it is between (0-33 is the first and second point, 34-66 is the second and third and 67 > is the third and forth) and then calculate the position of the object between these points.

It's a little more complicated, as you need to take into consideration the amount of time between the two points as a fraction of the over all time, but since the distance in time between the points is mostly even, it shouldn't play a big factor.

This is demonstrated here and here so you will have to forgive me for not reposting the code again.

Now, for my money, I'd also invest some time into getting to know an animation library like Timing Framework and/or Trident and/or Universal Tween Engine

这篇关于Java图像沿列表中的点移动并使用线性插值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆