如何围绕Java中的点旋转多边形/点

时间:2012-12-07 16:43:08

标签: java rotation polygon affinetransform

我一直在尝试围绕指定的中心点旋转多边形,但我尝试过的所有内容都失败了。我用谷歌搜索过,发现很多,但没有一个似乎有用。

我试图复制的结果与第一个答案相似

How to rotate an image gradually in Swing?

不同之处在于我需要多边形实际旋转,只是以一定角度绘制它不会切割它。 (这是简单的物理建模)

这是我的代码,我尝试过几种不同的方法

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JPanel;

public class rotationPanel extends JPanel {

    private static final int SIZE = 500;
    private static final Shape outline = makeShape();

    Point p;
    Point p2;
    Point p3;
    Point p4;
    Point[] points;
    Point[] npoints;

    Point center;
    Polygon poly;

    double angle;

    Timer timer;
    long start;
    long sleepTime;
    static int runTime;

    public rotationPanel(){
        setSize(500,500);
        setBackground(Color.DARK_GRAY);
        setVisible(true);

        runTime = 100;  //ms

        start = 0;
        sleepTime = 0;
        timer = new Timer();

        center = new Point(250,250);

        p = new Point(200,200);
        p2 = new Point(150,150);
        p3 = new Point(250,150);
        p4 = new Point(200,100);

        /*
        points = new Point[4];
        points[0]=p;
        points[1]=p2;
        points[2]=p3;
        points[3]=p4;

        npoints = new Point[4];
        npoints[0]=p;
        npoints[1]=p2;
        npoints[2]=p3;
        npoints[3]=p4;

        poly = new Polygon();
        */

    }

    public void mainloop(){
        start= System.currentTimeMillis();

        //rotate(points,2);

        p = rotatePoint(p,center);
        p2 = rotatePoint(p2,center);
        p3 = rotatePoint(p3,center);
        p4 = rotatePoint(p4,center);

        repaint();

        sleepTime = runTime -(System.currentTimeMillis()-start);
        System.out.println("Looped. Sleeping for:" +sleepTime+"ms");

        if(sleepTime>0)
            timer.schedule(new loop(), sleepTime);
        else
            mainloop();

    }

     private static Shape makeShape() {
            AffineTransform at = new AffineTransform();
            at.translate(SIZE/2, SIZE/2);
            at.scale(20, 20);
            at.rotate(Math.toRadians(35));
            return at.createTransformedShape(initPoly());       
        }

        /** Create a U shaped outline. */
        private static Polygon initPoly() {
            Polygon poly = new Polygon();
            poly.addPoint( 1,  0);
            poly.addPoint( 1, -2);
            poly.addPoint( 2, -2);
            poly.addPoint( 2,  1);
            poly.addPoint(-2,  1);
            poly.addPoint(-2, -2);
            poly.addPoint(-1, -2);
            poly.addPoint(-1,  0);
            return poly;
        }

    public void rotatePoint(Point pt, double rotationAngle){

        AffineTransform.getRotateInstance
        (Math.toRadians(rotationAngle), center.x, center.y)
                .transform(pt,pt);          
    }

    public Point rotatePoint(Point pt, Point center)
    {
        angle = (Math.toRadians(150));
        double cosAngle = Math.cos(angle);
        double sinAngle = Math.sin(angle);

        pt.x = center.x + (int) ((pt.x-center.x)*cosAngle-(pt.y-center.y)*sinAngle);
        pt.y = center.y + (int) ((pt.x-center.x)*sinAngle+(pt.y-center.y)*cosAngle);
        return pt;
    }

    public void rotate(Point[] pts, int angle){

        AffineTransform.getRotateInstance
        (Math.toRadians(angle), center.x, center.y)
                .transform(pts,0,npoints,0,4);

        points = new Point[4];
        points[0]=npoints[0];
        points[1]=npoints[1];
        points[2]=npoints[2];
        points[3]=npoints[3];

    }

    public void paintComponent(Graphics g) {
           super.paintComponent(g);  

           g.setColor(Color.BLUE);
           g.fillRect(center.x-4, center.y-4, 8, 8);

           g.setColor(Color.YELLOW);
           //g.fillRect(p.x-4, p.y-4, 8, 8);
           //g.fillRect(p2.x-4, p2.y-4, 8, 8);
           //g.fillRect(p3.x-4, p3.y-4, 8, 8);
           //g.fillRect(p4.x-4, p4.y-4, 8, 8);

           g.fillRect(p.x, p.y, 2, 2);
           g.fillRect(p2.x, p2.y, 2, 2);
           g.fillRect(p3.x, p3.y, 2, 2);
           g.fillRect(p4.x, p4.y, 2, 2);
    }

    class loop extends TimerTask{

        public void run() {
            mainloop();         
        }

    }

}

2 个答案:

答案 0 :(得分:9)

由于你没有帮助我,因此我不得不自己解决这个问题。我们走了:

正确的方法(或至少其中一个)是使用仿射变换到您想要旋转的多边形的点。问题是你不能一遍又一遍地旋转同一个多边形,因为它会因连续的圆整而严重变形。

所以诀窍是保持多边形的“原始版本”并始终旋转那个。

当然,这种方法仅在多次旋转多边形时才是关键。如果您只想旋转它,只需使用要旋转的多边形中的值即可。

这是我设法组建的一个小例子:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.RenderingHints;

import java.awt.geom.AffineTransform;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class rotationPanel extends JPanel {

    private static final long serialVersionUID = 117L;



    private static final int SIZE = 500;


    // point arrays which contain the points that are rotated around the center 
    Point[] points1;
    Point[] points2;
    Point[] points3;

    // The center of rotation  
    Point center;

    // the polygons being rotated
    Polygon poly1;
    Polygon poly2;
    Polygon poly3;

    // the angle of rotation
    double angle;


    Timer timer;
    long start;
    long sleepTime;
    static int runTime;





    public rotationPanel(){
        setSize(500,500);
        setBackground(Color.DARK_GRAY);
        setVisible(true);

        // time loop is set to run at fixed rate of 50 ms
        runTime = 50; 

        start = 0;
        sleepTime = 0;
        timer = new Timer();
        angle = 0;


        // initializing the arrays (not neccesary)
        points1 = getOriginalPoints(1);
        points3 = getOriginalPoints(3);
        points2 = getOriginalPoints(2);

        // setting the rotation to the middle of the screen
        center = new Point(250,250);


        // start the looping
        mainloop();

    }

    public void mainloop(){
        start= System.currentTimeMillis();

        // rotate the points the spcified angle and store the rotated
        //points to the correct array
        rotatePointMatrix(getOriginalPoints(1),angle,points1);
        rotatePointMatrix(getOriginalPoints(2),angle,points2);
        rotatePointMatrix(getOriginalPoints(3),angle,points3);

        // Make the points into a polygon
        poly1 = polygonize(points1);
        poly2 = polygonize(points2);
        poly3 = polygonize(points3);

        // increase the angle by one degree, resulting to rotation in the longer run
        angle++;



        if (angle>=360){
            angle=0;
        }



        // restatring the sequence 
        repaint();

        sleepTime = runTime -(System.currentTimeMillis()-start);
        System.out.println("Looped. Sleeping for:" +sleepTime+"ms");

        if(sleepTime>0)
            timer.schedule(new loop(), sleepTime);
        else
            mainloop();

    }





    public void rotatePointMatrix(Point[] origPoints, double angle, Point[] storeTo){

        /* We ge the original points of the polygon we wish to rotate
         *  and rotate them with affine transform to the given angle. 
         *  After the opeariont is complete the points are stored to the 
         *  array given to the method.
        */
        AffineTransform.getRotateInstance
        (Math.toRadians(angle), center.x, center.y)
                .transform(origPoints,0,storeTo,0,5);


    }

    public Polygon polygonize(Point[] polyPoints){

        //a simple method that makes a new polygon out of the rotated points
        Polygon tempPoly = new Polygon();

         for(int  i=0; i < polyPoints.length; i++){
             tempPoly.addPoint(polyPoints[i].x, polyPoints[i].y);
        }

        return tempPoly;

    }


    public Point[] getOriginalPoints(int type){

        /* In this example the rotated "polygon" are stored in this method. 
         * The Point is that if we want to rotate a polygon constatnly/frequently
         * we cannot use the values of an already rotated polygon as this will 
         * lead to the polygon deforming severely after few translations due 
         * to the points being constantly rounded. So the trick is to save the
         * original Points of the polygon and always rotate that one to the new
         *  angle instead of rotating the same one again and again.
        */
        Point[] originalPoints = new Point[5];

        if(type == 2){

        originalPoints[0]= new Point(200, 100);
        originalPoints[1]= new Point(250, 50);
        originalPoints[2]= new Point(300, 100);
        originalPoints[3]= new Point(300, 400);
        originalPoints[4]= new Point(200, 400);



        }

        else if(type == 1){

        originalPoints[0]= new Point(210, 150);
        originalPoints[1]= new Point(250, 150);
        originalPoints[2]= new Point(250, 190);
        originalPoints[3]= new Point(230, 220);
        originalPoints[4]= new Point(210, 190);


        }
        else{

            originalPoints[0]= new Point(250, 300);
            originalPoints[1]= new Point(290, 300);
            originalPoints[2]= new Point(290, 340);
            originalPoints[3]= new Point(270, 370);
            originalPoints[4]= new Point(250, 340);

        }


        return originalPoints;

    }


    public void paintComponent(Graphics g) {
           super.paintComponent(g);  

           Graphics2D g2d = (Graphics2D) g;

           g2d.setRenderingHint(                    
                    RenderingHints.KEY_ANTIALIASING,
                    RenderingHints.VALUE_ANTIALIAS_ON);

           g2d.setColor(Color.GRAY);
           g2d.fillPolygon(poly2);

           g2d.setColor(Color.yellow);
           g2d.fillPolygon(poly1);

           g2d.setColor(Color.yellow);
           g2d.fillPolygon(poly3);


           g2d.setColor(Color.WHITE);
           for(int  i=0; i < points1.length; i++){
                g2d.fillRect(points1[i].x-1, points1[i].y-1, 3, 3);
                g2d.fillRect(points3[i].x-1, points3[i].y-1, 3, 3);

            }

           g2d.setColor(Color.BLUE);
           g2d.fillOval(center.x-4, center.y-4, 8, 8);

           g2d.setColor(Color.yellow);
           g2d.drawString("Angle: "+angle, 10,450);

    }

    class loop extends TimerTask{


        public void run() {
            mainloop();

        }

    }


    public static void main(String[] args){
        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(new rotationPanel());
        f.setSize(500,500);
        f.setVisible(true);

    }

}

我希望这有帮助!如果遇到麻烦,请不要犹豫与我联系!

答案 1 :(得分:1)

这是一种简单的方法,该方法可以从一组围绕中心点以指定角度旋转的点构建多边形:

/**
 * Builds a polygon from a set of points, rotated around a point, at the
 * specified rotation angle.
 * 
 * @param centerX the int center x coordinate around which to rotate
 * @param centerY the int center y coordinate around which to rotate
 * @param xp the int[] of x points which make up our polygon points. This
 *           array is parallel to the yp array where each index in this array
 *           corresponds to the same index in the yp array.
 * @param yp the int[] of y points which make up our polygon points. This
 *           array is parallel to the xp array where each index in this array
 *           corresponds to the same index in the xp array.
 * @param rotationAngle the double angle in which to rotate the provided
 *                      coordinates (specified in degrees).
 * @return a Polygon of the provided coordinates rotated around the center point
 *         at the specified angle.
 * @throws IllegalArgumentException when the provided x points array is not the
 *                                  same length as the provided y points array
 */
private Polygon buildPolygon(int centerX, int centerY, int[] xp, int[] yp, double rotationAngle) throws IllegalArgumentException {
    // copy the arrays so that we dont manipulate the originals, that way we can
    // reuse them if necessary
    int[] xpoints = Arrays.copyOf(xp,xp.length);
    int[] ypoints = Arrays.copyOf(yp,yp.length);
    if(xpoints.length != ypoints.length){
        throw new IllegalArgumentException("The provided x points are not the same length as the provided y points.");
    }

    // create a list of Point2D pairs
    ArrayList<Point2D> list = new ArrayList();
    for(int i = 0; i < ypoints.length; i++){
        list.add(new Point2D.Double(xpoints[i], ypoints[i]));
    }

    // create an array which will hold the rotated points
    Point2D[] rotatedPoints = new Point2D[list.size()];

    // rotate the points
    AffineTransform transform = AffineTransform.getRotateInstance(Math.toRadians(rotationAngle), centerX, centerY);
    transform.transform(list.toArray(new Point2D[0]), 0, rotatedPoints, 0, rotatedPoints.length);

    // build the polygon from the rotated points and return it
    int[] ixp = new int[list.size()];
    int[] iyp = new int[list.size()];
    for(int i = 0; i < ixp.length; i++){
        ixp[i] = (int)rotatedPoints[i].getX();
        iyp[i] = (int)rotatedPoints[i].getY();
    }
    return new Polygon(ixp, iyp, ixp.length);
}