我正在尝试确定一个四边形状是否在另一个之上,并返回未被覆盖的数量的比率。我对“未覆盖”的定义是,如果在y轴上检查的那个上面没有其他形状,并且它们在x轴上有多少交叉。
示例:
在上图中,所需的输出应为0.6363。在110个像素中,70个与其上方的物体相交,并且70/110 = 0.6363
另一个例子:
在此示例中,所需的输出为0.3636。
我到目前为止尝试的是我从double out = 1;
开始,然后如果形状2的y轴小于形状1,我减去两个形状在x轴上相交的数量与out-=(c.getX2()-b.getX2())/Math.abs(c.getX1()-c.getX2());
但是,这似乎不起作用,我纠正代码的尝试似乎只是增加了越来越多的不必要的复杂性。我认为有一种更简单的方法来做我想做的事情,但我对几何学并不满意。
c
是正在检查的当前形状,b
是与之比较的形状。
if(((b.getX2() < c.getX2()) && (b.getX2()>c.getX1()))||((b.getX2()>c.getX2())&&(b.getX2()<c.getX1()))||((b.getX1()>c.getX2())&&(b.getX1()<c.getX1()))) {
if(b.getY2() < c.getY2()) {
if((b.getX2() < c.getX2()) && (b.getX2()>c.getX1())) {
out-= (c.getX2()-b.getX2())/Math.abs(c.getX1()-c.getX2());
}
if(((b.getX2()>c.getX2())&&(b.getX2()<c.getX1()))) {
out-=(b.getX2()-c.getX2())/Math.abs(c.getX1()-c.getX2());
}
if(((b.getX1()>c.getX2())&&(b.getX1()<c.getX1()))) {
out-=(c.getX2()-b.getX2())/Math.abs(c.getX1()-c.getX2());
}
}
}
答案 0 :(得分:1)
我认为你的方法很复杂,你可能会在所有不同的条件和配置中迷失方向。
如果我理解正确,那么最简单的解决方案是将计算基于两个形状的最小和最大X值。
旁注:
你没有说出你的'#34;形状&#34;对象b
和c
是。从您调用的方法来看,它们可能是java.awt.geom.Line2D
个对象,但这些对象并非真正的“四边形”#34;。在任何情况下,您都可以将最小值和最大值计算为
double bMinX = Math.min(b.getX1(), b.getX2());
double bMaxX = Math.max(b.getX1(), b.getX2());
double cMinX = Math.min(c.getX1(), c.getX2());
double cMaxX = Math.max(c.getX1(), c.getX2());
在下面的程序中,我使用实际的Shape
对象并调用getBounds2D
方法来获取边界框,这些框可以方便地提供这些最小/最大值。但您也可以手动执行此操作。
当您具有这些最小/最大值时,可以排除对象完全在另一个对象的左侧或完全右侧的情况。如果不是这种情况,则它们是重叠的。在这种情况下,您可以计算重叠的最小值和最大值,然后将其除以相关对象的宽度。
这是一个程序,根据您在问题中给出的坐标创建示例对象。您可以使用鼠标拖动对象。绘制重叠并打印其值。
计算在computeOverlap
方法中进行。
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ShapeOverlap
{
public static void main(String[] args) throws IOException
{
SwingUtilities.invokeLater(() -> createAndShowGUI());
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new ShapeOverlapPanel());
f.setSize(900,500);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class ShapeOverlapPanel extends JPanel
implements MouseListener, MouseMotionListener
{
private final List<Point2D> points0;
private final List<Point2D> points1;
private final List<Point2D> draggedPoints;
private Point previousMousePosition;
ShapeOverlapPanel()
{
points0 = new ArrayList<Point2D>();
points0.add(new Point2D.Double(160, 200));
points0.add(new Point2D.Double(180, 200));
points0.add(new Point2D.Double(270, 260));
points0.add(new Point2D.Double(250, 260));
points1 = new ArrayList<Point2D>();
points1.add(new Point2D.Double(200, 280));
points1.add(new Point2D.Double(220, 280));
points1.add(new Point2D.Double(310, 340));
points1.add(new Point2D.Double(290, 340));
draggedPoints = new ArrayList<Point2D>();
addMouseListener(this);
addMouseMotionListener(this);
}
@Override
protected void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
Shape s0 = createShape(points0);
Shape s1 = createShape(points1);
g.setColor(Color.RED);
g.fill(s0);
g.setColor(Color.BLUE);
g.fill(s1);
g.setColor(Color.GRAY);
drawOverlap(g, s0, s1);
double overlap = computeOverlap(s0, s1);
g.drawString("Overlap of red from blue: "+overlap, 10, 20);
}
private static double computeOverlap(Shape s0, Shape s1)
{
Rectangle2D b0 = s0.getBounds2D();
Rectangle2D b1 = s1.getBounds2D();
if (b0.getMaxX() < b1.getMinX())
{
System.out.println("Shape 0 is left of shape 1");
return Double.NaN;
}
if (b0.getMinX() > b1.getMaxX())
{
System.out.println("Shape 0 is right of shape 1");
return Double.NaN;
}
double overlapMinX = Math.max(b0.getMinX(), b1.getMinX());
double overlapMaxX = Math.min(b0.getMaxX(), b1.getMaxX());
double overlapSize = overlapMaxX - overlapMinX;
double relativeOverlap = overlapSize / b0.getWidth();
return relativeOverlap;
}
private void drawOverlap(Graphics2D g, Shape s0, Shape s1)
{
Rectangle2D b0 = s0.getBounds2D();
Rectangle2D b1 = s1.getBounds2D();
if (b0.getMaxX() < b1.getMinX())
{
return;
}
if (b0.getMinX() > b1.getMaxX())
{
return;
}
double overlapMinX = Math.max(b0.getMinX(), b1.getMinX());
double overlapMaxX = Math.min(b0.getMaxX(), b1.getMaxX());
g.drawLine((int)overlapMinX, 0, (int)overlapMinX, getHeight());
g.drawLine((int)overlapMaxX, 0, (int)overlapMaxX, getHeight());
}
private static Shape createShape(Iterable<? extends Point2D> points)
{
Path2D path = new Path2D.Double();
boolean first = true;
for (Point2D p : points)
{
if (first)
{
path.moveTo(p.getX(), p.getY());
first = false;
}
else
{
path.lineTo(p.getX(), p.getY());
}
}
path.closePath();
return path;
}
@Override
public void mouseDragged(MouseEvent e)
{
int dx = e.getX() - previousMousePosition.x;
int dy = e.getY() - previousMousePosition.y;
for (Point2D p : draggedPoints)
{
p.setLocation(p.getX() + dx, p.getY() + dy);
}
repaint();
previousMousePosition = e.getPoint();
}
@Override
public void mouseMoved(MouseEvent e)
{
}
@Override
public void mouseClicked(MouseEvent e)
{
}
@Override
public void mousePressed(MouseEvent e)
{
draggedPoints.clear();
Shape s0 = createShape(points0);
Shape s1 = createShape(points1);
if (s0.contains(e.getPoint()))
{
draggedPoints.addAll(points0);
}
else if (s1.contains(e.getPoint()))
{
draggedPoints.addAll(points1);
}
previousMousePosition = e.getPoint();
}
@Override
public void mouseReleased(MouseEvent e)
{
draggedPoints.clear();
}
@Override
public void mouseEntered(MouseEvent e)
{
}
@Override
public void mouseExited(MouseEvent e)
{
}
}