2016-04-29 194 views
-1

我有3天的時間尋找以螺旋方式在物體上移動,但我想我必須尋找在弧上移動物體的問題的一小部分。 看到我的問題:https://stackoverflow.com/questions/36917560/moving-rectangle-spiral-animation-java?noredirect=1#comment61428911_36917560沿着帶有java圖形的弧形路徑移動物體

現在,問題是我如何計算弧上存在的點。這是我的方法來獲得新的X和Y點(算法不代碼)

1-繪製弧形在Java中使用這種方法 g2d.fillArc(start_point_X_Arc,start_point_Y_Arc,width_of_arc,height_of_arc,start_angle,end_angle);

2-在相同的Start_point_X,Start_point_Y上繪製對象。在這裏,我將使用這種方法繪製一個矩形

g2d.drawRect(start_point_X_Rect,Start_point_Y_Rect,10,10);

3-因爲我使用一個計時器,它需要一個ActionListener actionPerformed方法將更新Start_point_X,Start_point_Y的值的矩形

與這裏的問題是我不能計算新X,Y值的值將會做問題的移動部分(我知道這些詞不是專業詞彙)。

正因爲如此我尋找如何計算電弧點,我發現對於圓形

X = center_X +半徑* COS(角度)

Y = center_y +半徑參數方程* sin(角度)

我知道這些公式可能會用來獲得新的積分,但我不擅長數學。

因此,我需要幫助做對象在弧形路徑中移動,我認爲這將幫助我做一個物體在螺旋路徑中移動。如果我的算法錯誤或任何錯誤,請給我建議,以簡單的方式做到這一點。

這是一個代碼,我讓它繪製一個圓弧&矩形,矩形在對角線路徑上移動。

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.awt.RenderingHints; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.geom.AffineTransform; 
import java.awt.geom.Arc2D; 
import java.awt.geom.Path2D; 
import java.awt.geom.PathIterator; 
import java.awt.geom.Point2D; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
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 class SpiralPath extends Path2D.Double { 

     public SpiralPath(int size) { 
      int numIterations = 5; 
      int arcGrowDelta = (size/numIterations)/2; 
      int arcWidth = 0; 

      int centerX = size/2; 
      int centerY = size/2; 
      moveTo(centerX, centerY); 

      for (int i = 0; i < numIterations; i++) { 
       append(new Arc2D.Double(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth, 2 * arcWidth, 180, 180, Arc2D.OPEN), true); 
       arcWidth += arcGrowDelta; 
       append(new Arc2D.Double(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth - arcGrowDelta, 2 * arcWidth, 0, 180, Arc2D.OPEN), true); 
      } 
     } 

    } 

    public class SpiralPath2 extends Path2D.Double { 

     public SpiralPath2(int size) { 
      int numIterations = 5; 
      int arcGrowDelta = (size/numIterations)/2; 
      int arcWidth = 0; 

      int centerX = size/2+200; 
      int centerY = size/2; 
      moveTo(centerX, centerY); 

      for (int i = 0; i < numIterations; i++) { 
       append(new Arc2D.Double(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth, 2 * arcWidth, 180, 180, Arc2D.OPEN), true); 
       arcWidth += arcGrowDelta; 
       append(new Arc2D.Double(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth - arcGrowDelta, 2 * arcWidth, 0, 180, Arc2D.OPEN), true); 
      } 
     } 

    } 

    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 SpiralPath spiralPath; 
     private final Rectangle box; 

     private List<Point2D> points; 
     private double angle; 
     private Point2D pos; 
     private int index; 

     private SpiralPath2 spiralPath2; 
     private final Rectangle box2; 

     private List<Point2D> points2; 
     private double angle2; 
     private Point2D pos2; 
     private int index2; 

     protected static final double PLAY_TIME = 5000; // 5 seconds... 

     private Long startTime; 

     public TestPane() { 
      spiralPath = new SpiralPath(150); 
      box = new Rectangle(0, 0, 10, 10); 

      points = new ArrayList<>(25); 
      PathIterator pi = spiralPath.getPathIterator(null, 0.01); 
      while (!pi.isDone()) { 
       double[] coords = new double[6]; 
       switch (pi.currentSegment(coords)) { 
        case PathIterator.SEG_MOVETO: 
        case PathIterator.SEG_LINETO: 
         points.add(new Point2D.Double(coords[0], coords[1])); 
         break; 
       } 
       pi.next(); 
      } 

      spiralPath2 = new SpiralPath2(200); 
      box2 = new Rectangle(0, 0, 10, 10); 

      points2 = new ArrayList<>(25); 
      PathIterator pi2 = spiralPath2.getPathIterator(null, 0.01); 
      while (!pi2.isDone()) { 
       double[] coords = new double[6]; 
       switch (pi2.currentSegment(coords)) { 
        case PathIterator.SEG_MOVETO: 
        case PathIterator.SEG_LINETO: 
         points2.add(new Point2D.Double(coords[0], coords[1])); 
         break; 
       } 
       pi2.next(); 
      } 

      pos = points.get(0); 
      pos2 = points2.get(0); 
      Timer timer = new Timer(40, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 

        if (startTime == null) { 
         startTime = System.currentTimeMillis(); 
        } 
        long playTime = System.currentTimeMillis() - startTime; 
        double progress = playTime/PLAY_TIME; 
        if (progress >= 1.0) { 
         progress = 1d; 
         ((Timer) e.getSource()).stop(); 
        } 

        int index = Math.min(Math.max(0, (int) (points.size() * progress)), points.size() - 1); 
        int index2 = Math.min(Math.max(0, (int) (points2.size() * progress)), points2.size() - 1); 

        pos = points.get(index); 
        pos2 = points2.get(index2); 
        if (index < points.size() - 1) { 
         angle = angleTo(pos, points.get(index + 1)); 
        } 

        if (index2 < points2.size() - 1) { 
         angle2 = angleTo(pos2, points2.get(index + 1)); 
        } 
        repaint(); 
       } 
      }); 

      timer.start(); 
     } 

     protected double angleTo(Point2D from, Point2D to) { 
      double angle = Math.atan2(to.getY() - from.getY(), to.getX() - from.getX()); 
      return angle; 
     } 

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

     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      applyQualityRenderingHints(g2d); 

      g2d.translate(20, 50); 
      g2d.draw(spiralPath); 
      g2d.draw(spiralPath2); 
      AffineTransform at = new AffineTransform(); 
      AffineTransform at2 = new AffineTransform(); 

      if (pos != null &&pos2!=null) { 

       Rectangle bounds = box.getBounds(); 
       at.rotate(angle, (bounds.width/2), (bounds.width/2)); 

       Path2D player = new Path2D.Double(box, at); 

       g2d.translate(pos.getX() - (bounds.width/2), pos.getY() - (bounds.height/2)); 
       g2d.setColor(Color.RED); 
       g2d.draw(player); 



      } 

      Rectangle bounds2 = box2.getBounds(); 
       at2.rotate(angle2, (bounds2.width/2), (bounds2.width/2)); 
       Path2D player2 = new Path2D.Double(box2, at2); 

       g2d.translate(pos2.getX() - (bounds2.width/2)+50, pos2.getY() - (bounds2.height/2)); 
       g2d.setColor(Color.RED); 
       g2d.draw(player2); 
      g2d.dispose(); 
     } 

    } 

    public static void applyQualityRenderingHints(Graphics2D g2d) { 

     g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); 
     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
     g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
     g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); 
     g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 
     g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
     g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
     g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); 

    } 

} 
+0

一種可能性是「作弊」一點(或者更重要的是,使用可用的API),如果可以生成螺旋的「路徑」,則可以使用「PathIterator」來查找所有點沿着那條路徑,然後你可以使用它作爲你的動畫/運動的基礎,[例如](http://stackoverflow.com/questions/32392095/how-to-rotate-a-rectangle-after-reaching-specified -position/32397121#32397121) – MadProgrammer

+0

@MadProgrammer如果你檢查我對你的解決方案的評論,看看我的更新代碼 –

回答

2

因此,根據this idea,您可以利用2D圖形API中已有的功能。

困難的部分是讓你的螺旋形狀設置爲Path對象,我們是幸運的,API是非常靈活的...

public class SpiralPath extends Path2D.Double { 

    public SpiralPath(int size) { 
     int numIterations = 5; 
     int arcGrowDelta = (size/numIterations)/2; 
     int arcWidth = 0; 

     int centerX = size/2; 
     int centerY = size/2; 
     moveTo(centerX, centerY); 

     for (int i = 0; i < numIterations; i++) { 
      append(new Arc2D.Double(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth, 2 * arcWidth, 180, 180, Arc2D.OPEN), true); 
      arcWidth += arcGrowDelta; 
      append(new Arc2D.Double(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth - arcGrowDelta, 2 * arcWidth, 0, 180, Arc2D.OPEN), true); 
     } 
    } 

} 

Sprial

現在我們的是,其餘的是(相對)簡單,因爲它遵循衆所周知的圖案......

Sprial

package javaapplication1.pkg005; 

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.EventQueue; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.Rectangle; 
import java.awt.RenderingHints; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.geom.AffineTransform; 
import java.awt.geom.Arc2D; 
import java.awt.geom.Path2D; 
import java.awt.geom.PathIterator; 
import java.awt.geom.Point2D; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
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 class SpiralPath extends Path2D.Double { 

     public SpiralPath(int size) { 
      int numIterations = 5; 
      int arcGrowDelta = (size/numIterations)/2; 
      int arcWidth = 0; 

      int centerX = size/2; 
      int centerY = size/2; 
      moveTo(centerX, centerY); 

      for (int i = 0; i < numIterations; i++) { 
       append(new Arc2D.Double(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth, 2 * arcWidth, 180, 180, Arc2D.OPEN), true); 
       arcWidth += arcGrowDelta; 
       append(new Arc2D.Double(centerX - arcWidth, centerY - arcWidth, 2 * arcWidth - arcGrowDelta, 2 * arcWidth, 0, 180, Arc2D.OPEN), true); 
      } 
     } 

    } 

    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 SpiralPath spiralPath; 
     private final Rectangle box; 

     private List<Point2D> points; 
     private double angle; 
     private Point2D pos; 
     private int index; 

     protected static final double PLAY_TIME = 5000; // 5 seconds... 

     private Long startTime; 

     public TestPane() { 
      spiralPath = new SpiralPath(150); 
      box = new Rectangle(0, 0, 10, 10); 

      points = new ArrayList<>(25); 
      PathIterator pi = spiralPath.getPathIterator(null, 0.01); 
      while (!pi.isDone()) { 
       double[] coords = new double[6]; 
       switch (pi.currentSegment(coords)) { 
        case PathIterator.SEG_MOVETO: 
        case PathIterator.SEG_LINETO: 
         points.add(new Point2D.Double(coords[0], coords[1])); 
         break; 
       } 
       pi.next(); 
      } 

      pos = points.get(0); 
      Timer timer = new Timer(40, new ActionListener() { 
       @Override 
       public void actionPerformed(ActionEvent e) { 

        if (startTime == null) { 
         startTime = System.currentTimeMillis(); 
        } 
        long playTime = System.currentTimeMillis() - startTime; 
        double progress = playTime/PLAY_TIME; 
        if (progress >= 1.0) { 
         progress = 1d; 
         ((Timer) e.getSource()).stop(); 
        } 

        int index = Math.min(Math.max(0, (int) (points.size() * progress)), points.size() - 1); 

        pos = points.get(index); 
        if (index < points.size() - 1) { 
         angle = angleTo(pos, points.get(index + 1)); 
        } 
        repaint(); 
       } 
      }); 

      timer.start(); 
     } 

     protected double angleTo(Point2D from, Point2D to) { 
      double angle = Math.atan2(to.getY() - from.getY(), to.getX() - from.getX()); 
      return angle; 
     } 

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

     protected void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      Graphics2D g2d = (Graphics2D) g.create(); 
      applyQualityRenderingHints(g2d); 
      int x = (getWidth() - spiralPath.getBounds().width)/2; 
      int y = (getHeight() - spiralPath.getBounds().height)/2; 
      g2d.translate(x, y); 
      g2d.draw(spiralPath); 
      AffineTransform at = new AffineTransform(); 

      if (pos != null) { 

       Rectangle bounds = box.getBounds(); 
       at.rotate(angle, (bounds.width/2), (bounds.width/2)); 

       Path2D player = new Path2D.Double(box, at); 

       g2d.translate(pos.getX() - (bounds.width/2), pos.getY() - (bounds.height/2)); 
       g2d.setColor(Color.RED); 
       g2d.draw(player); 

      } 
      g2d.dispose(); 
     } 

    } 

    public static void applyQualityRenderingHints(Graphics2D g2d) { 

     g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); 
     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
     g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
     g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); 
     g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); 
     g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); 
     g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
     g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); 

    } 

} 
+0

任何人都可以解釋downvote嗎?答案不回答操作問題嗎?我不是想幫助人嗎? – MadProgrammer

+0

我不知道是誰做的。主席先生,我有一個問題。如果我需要繪製位於彼此旁邊的2個不同螺旋,並且這兩個螺旋具有沿着它們中的每一個的螺旋路徑以不同速度移動的矩形。我試圖在你的代碼中複製元素,但我得到了一個經過翻譯和移位的螺旋。但是,這兩個矩形以相同的速度和方向移動。如果您查看了我上面更新的代碼,我將會對您感到滿意。 –

+0

螺旋和矩形的位置由g2d.translate控制 – MadProgrammer

0

嘗試了一個小程序(沒有計時器什麼都沒有就這面):

protected void paintComponent(Graphics g) { 
    super.paintComponent(g); 
    Graphics2D g2d = (Graphics2D)g; 
    g2d.setColor(Color.BLACK); 
    g2d.drawArc(200,200,200,200,0,90); 
    g2d.setColor(Color.magenta); 
    for(double t=0; t<Math.PI/2; t+=Math.PI/100) { 
     int x = 300 + (int)(100 * Math.cos(t)); 
     int y = 300 + (int)(100 * Math.sin(t)); 
     g.fillOval(x, y , 5 , 5); 
    } 
} 

如果您的弧是200寬和高,電弧從0到90(從右側X軸),這應該繪製弧上的點。

我想你可以概括這對你有什麼什麼中心寬度/高度等

你也可以改變角度

int y = 300 + (int)(100 * Math.sin(-t)); 

,如果你想向後畫。

+0

好吧,我會推廣它,但實際上我已經運行你的代碼,但它進入一個無限循環,只是打開白色框架和停止。請檢查它 –

+0

先生,只需重新定義你的t用雙t代替int t,代碼就可以正常工作。 我會盡量讓對象在這個點上移動 –

相關問題