Java 按正确顺序重新排列矩形的四个点
纵横比=高度/宽度总是>1(大多数情况下甚至>2),因此我希望如何旋转应该是清晰/精确的Java 按正确顺序重新排列矩形的四个点,java,sorting,Java,Sorting,纵横比=高度/宽度总是>1(大多数情况下甚至>2),因此我希望如何旋转应该是清晰/精确的 我在OpenCV/Java中有一个RotatedRect对象。 我可以得到一个数组,其中包含4个类型为Point和Point定义x/y值的对象 现在我想对这4个点进行排序,使左上角的点是数组的第一个元素,然后顺时针,使上下角的点是第四个元素 我假设矩形没有旋转太多(只是一些小角度),例如 在这个例子中,我已经指出了哪个点是左上角(TL) 怎么做 你不需要特别告诉我OpenCV等,只要假设你有两个数组 i
我在OpenCV/Java中有一个
RotatedRect
对象。我可以得到一个数组,其中包含4个类型为Point和Point定义x/y值的对象 现在我想对这4个点进行排序,使左上角的点是数组的第一个元素,然后顺时针,使上下角的点是第四个元素 我假设矩形没有旋转太多(只是一些小角度),例如 在这个例子中,我已经指出了哪个点是左上角(TL) 怎么做 你不需要特别告诉我OpenCV等,只要假设你有两个数组
int[] x = new int[4];
int[] y = new int[4];
而
n
-th点具有坐标(x[n-1],y[n-1])
。然后我可以专门为OpenCV做这件事。搜索具有最高y值的2个点,其中一个始终是定义中的TL(宽度<高度和小角度(不高于45°)
按y值的降序对数组排序,并获取具有第二个最高y值的元素
如果此点的x值最低,则定义右侧图片(1)。否则,具有最高值的点是TL,并定义左侧图片(2)
现在得到顺时针的顺序,其中TL是第一个元素
在案例(1)中:更改排序数组的最后2个元素的位置
情况(2):更改前2个元素的位置
这是真的,因为你的定义,但我不能用正确的数学方法解释它。我只是尝试了一种方法。我不确定它是“更简单”还是在任何其他方面比你的“更好”,但我将它作为一个建议发布在这里: 您可以计算矩形的中心。然后您可以移动矩形,使其中心位于原点。然后您可以使用
Math.atan2
方法计算每个点与x轴的角度。这里最简洁的一点是:它返回的角度范围为-PI…+PI,与您所需的顺序完全匹配:upper左点将具有“最负”角度,左下点将具有“最正”角度
此描述仅用于说明。其中一些步骤(尤其是“移动”矩形)不必显式完成
但是:在此示例中,您可以通过鼠标单击来设置角点。每个点都将标记其索引和角度,如上所述。当设置第四个点时,这些点将相应地重新排序,并显示结果索引/角度
就我所见,结果似乎是你想要计算的
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class RectanglePointReorderingTest
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new RectanglePointReorderingPanel());
f.setSize(800, 800);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
static Point2D computeCenter(List<Point2D> points)
{
double x = 0;
double y = 0;
for (Point2D p : points)
{
x += p.getX();
y += p.getY();
}
x /= points.size();
y /= points.size();
return new Point2D.Double(x, y);
}
static double computeAngle(Point2D center, Point2D point)
{
double dx = point.getX() - center.getX();
double dy = point.getY() - center.getY();
double angleRad = Math.atan2(dy, dx);
return angleRad;
}
static Comparator<Point2D> createComparator(Point2D center)
{
final Point2D finalCenter =
new Point2D.Double(center.getX(), center.getY());
return new Comparator<Point2D>()
{
@Override
public int compare(Point2D p0, Point2D p1)
{
double angle0 = computeAngle(finalCenter, p0);
double angle1 = computeAngle(finalCenter, p1);
return Double.compare(angle0, angle1);
}
};
}
static void sortPoints(List<Point2D> points)
{
Collections.sort(points, createComparator(computeCenter(points)));
}
}
class RectanglePointReorderingPanel extends JPanel implements MouseListener
{
private List<Point2D> points = new ArrayList<Point2D>();
public RectanglePointReorderingPanel()
{
addMouseListener(this);
}
@Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setColor(Color.BLACK);
if (points.size() < 4)
{
g.drawString("Click to create points", 20, 20);
}
else
{
g.drawString("Sorted points. Click again to clear.", 20, 20);
}
for (int i=0; i<points.size(); i++)
{
Point2D point = points.get(i);
double x = point.getX();
double y = point.getY();
g.setColor(Color.RED);
g.fill(new Ellipse2D.Double(x-5,y-5,10,10));
g.setColor(Color.BLACK);
double angleRad =
RectanglePointReorderingTest.computeAngle(
RectanglePointReorderingTest.computeCenter(points), point);
String angleString = String.valueOf((int)Math.toDegrees(angleRad));
g.drawString(String.valueOf(i)+" ("+angleString+")", (int)x+5, (int)y+5);
}
}
@Override
public void mouseClicked(MouseEvent e)
{
if (points.size() == 4)
{
points.clear();
repaint();
}
else
{
points.add(e.getPoint());
if (points.size() == 4)
{
RectanglePointReorderingTest.sortPoints(points);
}
repaint();
}
}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) { }
@Override
public void mousePressed(MouseEvent e) { }
@Override
public void mouseReleased(MouseEvent e) { }
}
导入java.awt.Color;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.event.MouseEvent;
导入java.awt.event.MouseListener;
导入java.awt.geom.Ellipse2D;
导入java.awt.geom.Point2D;
导入java.util.ArrayList;
导入java.util.Collections;
导入java.util.Comparator;
导入java.util.List;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.SwingUtilities;
公共类矩形点重新排序测试
{
公共静态void main(字符串[]args)
{
SwingUtilities.invokeLater(新的Runnable()
{
@凌驾
公开募捐
{
createAndShowGUI();
}
});
}
私有静态void createAndShowGUI()
{
JFrame f=新的JFrame();
f、 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f、 getContentPane().add(新的矩形点重新排序面板());
f、 设置大小(800800);
f、 setLocationRelativeTo(空);
f、 setVisible(真);
}
静态点2D计算中心(列出点)
{
双x=0;
双y=0;
对于(点2D p:点)
{
x+=p.getX();
y+=p.getY();
}
x/=points.size();
y/=points.size();
返回新的点2d.Double(x,y);
}
静态双计算角(点2D中心,点2D点)
{
double dx=point.getX()-center.getX();
double dy=point.getY()-center.getY();
双角度rad=数学atan2(dy,dx);
返回角度;
}
静态比较器createComparator(点2D中心)
{
最终点2D最终中心=
新的Point2D.Double(center.getX(),center.getY());
返回新的比较器()
{
@凌驾
公共整数比较(点2D p0,点2D p1)
{
双角度0=计算角度(最终中心,p0);
双角度1=计算角度(最终中心,p1);
返回双精度。比较(角度0,角度1);
}
};
}
静态无效排序点(列表点)
{
排序(点,createComparator(计算中心(点));
}
}
类RectanglePointReorderingPanel扩展JPanel实现MouseListener
{
私有列表点=新的ArrayList();
公共矩形点重新排序面板()
{
addMouseListener(这个);
}
@凌驾
受保护的组件(图形组)
{
超级油漆组件(gr);
Graphics2D g=(Graphics2D)gr;
g、 设置颜色(颜色为黑色);
if(points.size()<4)
{
g、 抽绳(“点击创建点”,20,20);
}
其他的
{
g、 抽绳(“已排序的点。再次单击以清除。”、20、20);
}
对于(int i=0;iAnswer)
如果您知道,则有一个非常简单的解决方案:
-45
roundedRect.size.height>roundedRect.size.width
如果这是真的,那么按顺时针顺序排列的点将始终按以下顺序排列:
pts[0], pts[3], pts[2], pts[1]
作为旁白,如果
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.opencv.core.Point;
import org.opencv.core.RotatedRect;
import org.opencv.core.Size;
public class TestFrame extends JFrame {
public static void main(String... args) {
final TestFrame frame = new TestFrame();
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
frame.setVisible(true);
}
});
}
private RectComponent rect;
public TestFrame() {
JPanel containerPane = new JPanel(new BorderLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
rect = new RectComponent();
containerPane.add(rect);
setContentPane(containerPane);
setSize(400,400);
new Timer(100, rect).start();
}
public class RectComponent extends JComponent implements ActionListener {
private RotatedRect rect = new RotatedRect(new Point(0,0), new Size(1, 3), 0);
private final Point[] pts = new Point[4];
@Override
protected void paintComponent(Graphics g) {
rect.points(pts);
printPoints();
Dimension size = getSize();
drawRectLine(g, pts[0], pts[1], size);
drawRectLine(g, pts[1], pts[2], size);
drawRectLine(g, pts[2], pts[3], size);
drawRectLine(g, pts[0], pts[3], size);
}
private void printPoints() {
System.out.format("A: %d, TL: %s, TR: %s, BR: %s, BL%s%n",
(int) (rect.angle + (rect.angle < 0 ? -1e-6 : 1e-6)), // Stupid doubles, stupid rounding error
pointToString(pts[0]),
pointToString(pts[3]),
pointToString(pts[2]),
pointToString(pts[1]));
}
private String pointToString(Point p) {
return String.format("{%.2f,%.2f}",p.x, p.y);
}
private void drawRectLine(Graphics g, Point left, Point right, Dimension size) {
g.drawLine(scale(left.x, size.width), scale(left.y, size.height),
scale(right.x, size.width), scale(right.y, size.height));
}
private int scale(double value, int coord) {
return (int) (value * coord) / 4 + coord / 2;
}
@Override
public void actionPerformed(ActionEvent e) {
rect.angle += 1;
if(rect.angle > 44) rect.angle = -44;
repaint();
}
}
}
shortest distance = top right point
longest distance = bottom right point
middle distance = bottom left point
point[0] - bottom left
point[1] - top left
point[2] - top right
point[3] - bottom right
public void points(Point pt[])
{
double _angle = angle * Math.PI / 180.0;
double b = (double) Math.cos(_angle) * 0.5f;
double a = (double) Math.sin(_angle) * 0.5f;
pt[0] = new Point(
center.x - a * size.height - b * size.width,
center.y + b * size.height - a * size.width);
pt[1] = new Point(
center.x + a * size.height - b * size.width,
center.y - b * size.height - a * size.width);
pt[2] = new Point(
2 * center.x - pt[0].x,
2 * center.y - pt[0].y);
pt[3] = new Point(
2 * center.x - pt[1].x,
2 * center.y - pt[1].y);
}
// Distance (x1, y1) to (x2, y2) = abs( sqrt( (x2-x1)^2 + (y2-y1)^2 ) )
// Note:This is a quite literal translation of the formula, there are more efficient ways.
public static final double pointsDist(Point pt1, Point pt2){
return Math.abs( Math.sqrt( Math.pow((double) (pt2.x - pt1.x), 2) + Math.pow((double) (pt2.y - pt1.y), 2) ) );
}