如何在 Java 中围绕一个点旋转多边形/点
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13767301/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to rotate a polygon/points around a point in Java
提问by TRU7H
I've been trying to rotate a polygon around a specified center point but everything I've tried has failed miserably. I've googled for example and found many but not a single one seems to work.
我一直在尝试围绕指定的中心点旋转多边形,但我尝试过的一切都失败了。例如,我用谷歌搜索,发现很多但没有一个似乎有效。
The result I'm trying to replicate is similar with the first answer to this
我试图复制的结果与对此的第一个答案相似
How to rotate an image gradually in Swing?
The difference is that I need the polygon to actually rotate, just drawing it in an angle won't cut it. (it's for simple physics modelling)
不同之处在于我需要多边形来实际旋转,只是以一个角度绘制它不会切割它。(它用于简单的物理建模)
Here's my code, with several different methods I've tried to implement
这是我的代码,我尝试实现了几种不同的方法
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();
}
}
}
回答by TRU7H
As you didn't help me vary much I was forced to figure this out by myself. Here we go:
由于你没有帮助我改变太多,我被迫自己解决这个问题。开始了:
The correct approach (or at least one of them) is to use affine transform to the points of the polygon you wish to rotate. The catch is that you cannot rotate the same polygon over and over again as it will severely deform due to the continuous rounding.
正确的方法(或至少其中之一)是对要旋转的多边形的点使用仿射变换。问题是你不能一遍又一遍地旋转同一个多边形,因为它会由于连续舍入而严重变形。
So the trick is to keep " an original version" of the polygon and always rotate that one.
所以诀窍是保持多边形的“原始版本”并始终旋转那个。
Of course, this approach is only critical when rotating the polygon several times. If you want to only rotate it once you can simply use the values from the polygon you want to rotate.
当然,这种方法仅在多次旋转多边形时才重要。如果您只想旋转一次,您可以简单地使用要旋转的多边形中的值。
Here's a little example I managed to put together:
这是我设法拼凑起来的一个小例子:
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);
}
}
I hope this helps! Don't hesitate to contact me if you run into trouble!
我希望这有帮助!如果您遇到麻烦,请随时与我联系!
回答by verydul
Here is a simple method to build a polygon from a set of points, rotated around a center point, at a specified angle:
这是一种从一组点构建多边形的简单方法,围绕中心点以指定角度旋转:
/**
* 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);
}