java - 确定一个形状是否位于另一个形状之上

标签 java geometry coordinate

我正在尝试确定一个四​​边形状是否高于另一个形状,并返回未覆盖的数量的比率。我对“未覆盖”的定义是,在 y 轴上检查的形状上方是否没有其他形状,以及它们在 x 轴上是否相交。

示例:

two shapes

在上图中,所需的输出应为 0.6363。在 110 个像素中,有 70 个与其上方的对象相交,并且 70/110=0.6363

另一个例子:

example 2

在此示例中,所需的输出为 0.3636。

到目前为止,我尝试的是从 double out = 1; 开始,然后如果形状 2 的 y 轴小于形状 1,我减去两个形状的数量从比率与 out-=(c.getX2()-b.getX2())/Math.abs(c.getX1()-c.getX2());< 的某些变体在 x 轴上相交

但是,这似乎不起作用,而且我纠正代码的尝试似乎只是增加了越来越多不必要的复杂性。我认为有一种更简单的方法可以完成我想做的事情,但我不擅长几何。

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());
        }
    }
}

最佳答案

我认为您的方法过于复杂,您可能会迷失在所有不同的可能条件和配置中。

如果我理解正确,那么最简单的解决方案是根据两种形状的最小和最大 X 值进行计算。

<小时/>

旁注:

您没有说明您的“形状”对象 bc 是什么类型。从您调用的方法来看,它们可能是 java.awt.geom.Line2D物体,但这些并不是真正的“四面体”。在任何情况下,您都可以计算最小值和最大值:

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 方法来获取边界框,该边界框可以方便地提供这些最小/最大值。但您也可以手动执行此操作。

<小时/>

当您获得这些最小/最大值时,您可以排除一个对象完全位于另一个对象的左侧或完全右侧的情况。如果情况并非如此,则它们是重叠的。在这种情况下,您可以计算重叠的最小值和最大值,然后将其除以相关对象的宽度。

这是一个程序,其中根据您在问题中给出的坐标创建示例对象。您可以使用鼠标在对象周围拖动。绘制重叠部分并打印其值。

Overlap

计算在 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)
    {
    }


}

关于java - 确定一个形状是否位于另一个形状之上,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48633950/

相关文章:

java - YAJSW Java初学者示例

html - 如何仅使用 CSS 创建对话泡泡

math - 查找至少部分位于任意方向矩形内的所有像素

python - 将故事分配给游戏中的位置的最佳方式?

3D坐标绘图

java - 不同 JVM 中的 Java Web 应用程序中的函数调用

java - 如何确定 Guava 缓存中是否存在某个键,以便我不覆盖它?

c# - 仅根据在 lucene 中术语出现次数较多的文档计算分数

java - Java 光标周围的黄色圆圈

system - 将表示从一个坐标系旋转到另一个坐标系的四元数转换