使图像指向Java中的特定位置

时间:2018-06-22 11:11:56

标签: java rotation graphics2d

将其标记为重复之前

我在互联网上进行了大量搜索,并尝试了每种解决方案,但没有人以与我相同的方式进行。在我的情况下,轮换是一个单独的课程。

我创建了一个继承JLabel类的java类,在我的类中有一个箭头BufferedImage,我可以使用paintComponent(Graphics g)方法绘制该箭头。

我正在尝试使箭头指向特定点(这是通过其他方法获得的),但是出了点问题,箭头旋转了错误的方向。

我认为:,因为imageLocation是相对于标签的,所以计算不正确。

这是我的代码:

package pkg1;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;
import javax.swing.*;

public final class ImageLabel extends JLabel {

   private float angle = 0.0f; // in radians
   private Point imageLocation = new Point();
   private File imageFile = null;
   private Dimension imageSize = new Dimension(50, 50);
   private BufferedImage bi;

   private BufferedImage resizeImage(BufferedImage originalImage, int img_width, int img_height) {
      int type = originalImage.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : originalImage.getType();
      BufferedImage resizedImage = new BufferedImage(img_width, img_height, type);
      Graphics2D g = resizedImage.createGraphics();
      g.drawImage(originalImage, 0, 0, img_width, img_height, null);
      g.dispose();

      return resizedImage;
   }

   @Override
   public void paintComponent(Graphics g) {
      super.paintComponent(g);
      if (bi == null) {
         return;
      }
      imageLocation = new Point(getWidth() / 2 - bi.getWidth() / 2, getHeight() / 2 - bi.getHeight() / 2);
      Graphics2D g2 = (Graphics2D) g;
      g2.rotate(angle, imageLocation.x + bi.getWidth() / 2, imageLocation.y + bi.getHeight() / 2);
      g2.drawImage(bi, imageLocation.x, imageLocation.y, null);
   }

   public void rotateImage(float angle) { // rotate the image to specific angle
      this.angle = (float) Math.toRadians(angle);
      repaint();
   }

   public void pointImageToPoint(Point target) {
      calculateAngle(target);
      repaint();
   }

   private void calculateAngle(Point target) {
      // calculate the angle from the center of the image
      float deltaY = target.y - (imageLocation.y + bi.getHeight() / 2);
      float deltaX = target.x - (imageLocation.x + bi.getWidth() / 2);
      angle = (float) Math.atan2(deltaY, deltaX);
      if (angle < 0) {
         angle += (Math.PI * 2);
      }
   }
}

1 个答案:

答案 0 :(得分:2)

好吧,所以有两件事突然出现在我身上...

  1. 如果从标签上下文之外获取Point,则必须将点转换为组件坐标上下文
  2. calculateAngle似乎是错误的

所以从...开始

private void calculateAngle(Point target) {
  // calculate the angle from the center of the image
  float deltaY = target.y - (imageLocation.y + bi.getHeight() / 2);
  float deltaX = target.x - (imageLocation.x + bi.getWidth() / 2);
  angle = (float) Math.atan2(deltaY, deltaX);
  if (angle < 0) {
     angle += (Math.PI * 2);
  }
}

angle = (float) Math.atan2(deltaY, deltaX);应该为angle = (float) Math.atan2(deltaX, deltaY);(交换增量)

您会发现您需要将结果调整180度才能使图像指向正确的方向

angle = Math.toRadians(Math.toDegrees(angle) + 180.0);

好的,我是个白痴,但是可以用:P

我还将利用AffineTransform来平移和旋转图像-就个人而言,我发现它更易于处理。

在示例中,我有点作弊。我将AffineTransform的平移设置为组件的中心,然后围绕新的原点(0x0)旋转上下文。然后,我将图像的偏移量绘制为高度/宽度的一半,从而使其看起来像图像围绕其中心旋转一样-很晚了,我很累了,它可以工作:P

Point at me

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;

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 ImageLabel label;

        public TestPane() {
            setLayout(new GridBagLayout());
            label = new ImageLabel();
            add(label);

            addMouseMotionListener(new MouseAdapter() {
                @Override
                public void mouseMoved(MouseEvent e) {
                    label.pointImageToPoint(e.getPoint(), TestPane.this);
                }
            });
        }

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

    }

    public final class ImageLabel extends JLabel {

        private double angle = 0;
        private Point imageLocation = new Point();
        private File imageFile = null;
        private Dimension imageSize = new Dimension(50, 50);
        private BufferedImage bi;

        public ImageLabel() {
            setBorder(new LineBorder(Color.BLUE));
            bi = new BufferedImage(50, 50, BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2d = bi.createGraphics();
            g2d.setColor(Color.RED);
            g2d.drawLine(25, 0, 25, 50);
            g2d.drawLine(25, 0, 0, 12);
            g2d.drawLine(25, 0, 50, 12);
            g2d.dispose();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(bi.getWidth(), bi.getHeight());
        }

        protected Point centerPoint() {
            return new Point(getWidth() / 2, getHeight() / 2);
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (bi == null) {
                return;
            }
            Graphics2D g2d = (Graphics2D) g.create();
            AffineTransform at = g2d.getTransform();
            Point center = centerPoint();
            at.translate(center.x, center.y);
            at.rotate(angle, 0, 0);
            g2d.setTransform(at);
            g2d.drawImage(bi, -bi.getWidth() / 2, -bi.getHeight() / 2, this);
            g2d.dispose();
        }

        public void rotateImage(float angle) { // rotate the image to specific angle
            this.angle = (float) Math.toRadians(angle);
            repaint();
        }

        public void pointImageToPoint(Point target, JComponent fromContext) {
            calculateAngle(target, fromContext);
            repaint();
        }

        private void calculateAngle(Point target, JComponent fromContext) {
            // calculate the angle from the center of the image
            target = SwingUtilities.convertPoint(fromContext, target, this);
            Point center = centerPoint();
            float deltaY = target.y - center.y;
            float deltaX = target.x - center.x;
            angle = (float) -Math.atan2(deltaX, deltaY);
            angle = Math.toRadians(Math.toDegrees(angle) + 180.0);
            repaint();
        }
    }
}

我只想补充一点,为此目的使用JLabel是过大的,简单的JPanelJComponent会完成相同的工作,并且负担少得多,说