【问题标题】:Algorithm to verify if a shape is inside another - javafx验证形状是否在另一个形状内的算法 - javafx
【发布时间】:2017-01-25 23:29:42
【问题描述】:

我有一个矩形和一个圆形。我需要验证一个矩形是否在该圆圈内。

我尝试了 Shape.intersects 但 intersects 被检查为数字 1。

有人知道javafx中的这种算法吗?

举例来说,图中只有矩形1、2、3、4在圆内。

感谢您的帮助。

【问题讨论】:

  • 什么?矩形不完全在圆圈内
  • @Natecat 是的,你的权利。编辑我的问题。
  • 你是如何绘制这些对象的?按 X 和 Y 坐标?

标签: java algorithm javafx


【解决方案1】:

解决方案

这个解决方案背后的基本思想是,任何多边形都包含在任何(见 cmets)形状中,只要多边形内的每个点都在该形状内。如果多边形的至少一个点在形状内,您尝试使用的intersects() 方法将返回true。您已经发现它会起作用,但它也会为任何部分相交的形状提供误报。为了解决这个问题,我们定义了自己的交叉测试,它会查看所有点。

这可以概括为扫描任何给定多边形以查找具有任何给定形状的“总交点”:

public boolean totalIntersects(Polygon poly, Shape testShape) {
    List<Point> points = flatDoublesToPoints(poly.getPoints());
    boolean inside = true; // If this is false after testing all points, the poly has at least one point outside of the shape.
    for(Point point : points) {
        if(!testShape.intersects(point.x, point.y, 1, 1)) { // The 3rd and 4th parameters here are "width" and "height". 1 for a point.
            inside = false;
        }
    }
    return inside;
}

其中flatDoublesToPoints()Point 定义为:

private List<Point> flatDoublesToPoints(List<Double> flatDoubles) {
    List<Point> points = new ArrayList<>();
    for(int i = 0; i < flatDoubles.size(); i += 2) {
        points.add(new Point(flatDoubles.get(i), flatDoubles.get(i + 1)));
    }
    return points;
}

class Point {
    public double x, y;
    
    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

flatDoublesToPoints() 用于将“平面”{x1, y1, x2, y2, x3, y3...} 多边形列表拆分为更易于理解的数据结构。但是,如果您要进行大量比较,则跳过此步骤可能会有所帮助,出于内存原因直接对“平面列表”进行操作。

应用

以下将其他方法应用于与您的情况极为相似的情况。 (不准确,因为我没有你的代码。)

public class Main extends Application {
    
    public static final int SIZE = 600;
    
    @Override
    public void start(Stage primaryStage) throws Exception {
        Pane rootPane = new Pane();

        List<Rectangle> rects = new ArrayList<>();
        for (int j = 0; j < 2; j++) {
            for(int i = 0; i < 5; i++) {
                Rectangle r = new Rectangle(i * 100, j == 0 ? 0 : 300, 100, 200);
                r.setFill(Color.BEIGE);
                r.setStroke(Color.BLACK);
                rects.add(r);
            }
        }
        rootPane.getChildren().addAll(rects);
    
        Circle circle = new Circle(350, 100, 200);
        circle.setStroke(Color.BLACK);
        circle.setFill(null);
        rootPane.getChildren().add(circle);
    
        List<Polygon> polys = new ArrayList<>();
        for(Rectangle rect : rects) {
            polys.add(rectangleToPolygon(rect));
        }
        List<Polygon> intersects = getTotalIntersections(polys, circle);
        System.out.println(intersects);
        
        primaryStage.setScene(new Scene(rootPane, SIZE, SIZE));
        primaryStage.show();
    }
    
    public List<Polygon> getTotalIntersections(List<Polygon> polys, Shape testShape) {
        List<Polygon> intersections = new ArrayList<>();
        for(Polygon poly : polys) {
            if(totalIntersects(poly, testShape)) {
                intersections.add(poly);
            }
        }
        return intersections;
    }
    
    public static Polygon rectangleToPolygon(Rectangle rect) {
        double[] points = {rect.getX(), rect.getY(),
                            rect.getX() + rect.getWidth(), rect.getY(),
                            rect.getX() + rect.getWidth(), rect.getY() + rect.getHeight(),
                            rect.getX(), rect.getY() + rect.getHeight()};
        return new Polygon(points);
    }
    
    public static void main(String[] args) {
        Main.launch(args);
    }
}

此代码将打印以下内容:

[Polygon[points=[200.0, 0.0, 300.0, 0.0, 300.0, 200.0, 200.0, 200.0], fill=0x000000ff], Polygon[points=[300.0, 0.0, 400.0, 0.0, 400.0, 200.0, 300.0, 200.0], fill=0x000000ff], Polygon[points=[400.0, 0.0, 500.0, 0.0, 500.0, 200.0, 400.0, 200.0], fill=0x000000ff]]

标记为 2、3 和 4 的三个多边形是哪一个。

【讨论】:

  • 感谢您的回答。我会努力的!
  • 没问题。如果您对上面的代码有任何疑问,请告诉我。
  • 您的方法的基本问题是基本假设是错误的。这仅适用于凸多边形,但如果外部多边形是凹多边形则不然。那么内部多边形可能与外部多边形相交,尽管它的所有点都在外部多边形内部。
  • 嗯。我确实尝试过考虑是否导致内部形状凹入的问题,但我忘记了外部形状也是凹入的。我想这就是我试图把它抽象出来的结果。有没有办法在不计算和比较内部多边形的每个点的情况下解决这个问题,或者我应该给算法本身添加一个约束?
【解决方案2】:

我认为JavaFX不会针对这种情况有一些特殊的方法。

要绘制该圆,您需要中心坐标(X_c, Y_c) 和半径(R)

要绘制矩形,您需要有角度点的坐标((X_1, Y_1)(X_2, Y_2) 等)。

那么你只需要检查矩形的所有点是否都在圆内:

(X_1 - X_c)^2 + (Y_1 - Y_c)^2 < R^2
(X_2 - X_c)^2 + (Y_2 - Y_c)^2 < R^2
...

【讨论】:

  • 感谢您的回答。我有问题。左上角点是 x_1?右上角的点是y_1?
  • 请注意,您需要检查所有 4 个矩形角。
  • @YoungrokLim,每个点都有自己的XY。假设左上点坐标为(X_1, Y_1),右上为(X_2, Y_2)
【解决方案3】:

试试这个:

import javafx.geometry.Point2D;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Rectangle;

/*
 Check if a rectangle is contained with in a circle by checking 
 all rectangle corners.
 For the rectangle to be contained in a circle, all its corners should be
 in a distance smaller or equal to the circle's radius, from the circle's center. 
 Note:
 Requires some more testing. I tested only a few test cases.
 I am not familiar with javafx. This solution does not take into 
 calculation rectangle's arc or other attributes I may not be aware of.
 */
public class Test{

    //apply 
    public static void main(String[] args){

        Circle circle = new Circle(0 ,0, 100);
        Rectangle rec = new Rectangle(0, 0, 50 , 50);

        System.out.println("Is rectungle inside the circle ? "
                                     + isContained(circle,rec));
    }

    //check if rectangle is contained within a circle
    private static boolean isContained(Circle circle,Rectangle rec) {

        boolean isInside = true;

        //get circle center & radius
        Point2D center = new Point2D(circle.getCenterX(), circle.getCenterY());
        double radius= circle.getRadius();

        Point2D[] corners = getRectangleCorners(rec);

        for(Point2D corner : corners) {

            //if any corner falls outside the circle
            //the rectangle is not contained in the circle
            if(distanceBetween2Points(corner, center) > radius) {
                return false;
            }
        }
        return isInside;
    }

    //calculate distance between two points
    //(updated a per fabian's suggestion)
    private static double distanceBetween2Points
                            (Point2D corner, Point2D center) {
        return corner.distance(center);
    }

    private static Point2D[] getRectangleCorners(Rectangle rec) {

        Point2D[] corners = new Point2D[4];
        corners[0] = new Point2D(rec.getX(),                  rec.getY());
        corners[1] = new Point2D(rec.getX()+ rec.getWidth() , rec.getY());
        corners[2] = new Point2D(rec.getX()+ rec.getWidth(),  rec.getY()+ rec.getHeight());
        corners[3] = new Point2D(rec.getX(),                  rec.getY()+ rec.getHeight());

        return corners;
    }
}

【讨论】:

  • 感谢您的回答。我会尝试:D
  • 我有问题。 double deltaX = center.getX() -corner.getX() 中的 distanceBetween2Points 方法;双 deltaY = center.getY() -corner.getY();对吗,getX(), getY()?
  • 是的。 X坐标差,Y坐标差。
  • 我得到了错误。对于 Point2D 类型,方法 getX() 未定义。
  • 如果你使用我添加到代码import javafx.geometry.Point2D;的导入则不会@
【解决方案4】:

这里有一个简单的解决方案:https://stackoverflow.com/a/8721483/1529139

复制粘贴到这里:

class Boundary {
    private final Point[] points; // Points making up the boundary
    ...


    /**
     * Return true if the given point is contained inside the boundary.
     * See: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
     * @param test The point to check
     * @return true if the point is inside the boundary, false otherwise
     *
     */
    public boolean contains(Point test) {
      int i;
      int j;
      boolean result = false;
      for (i = 0, j = points.length - 1; i < points.length; j = i++) {
        if ((points[i].y > test.y) != (points[j].y > test.y) &&
            (test.x < (points[j].x - points[i].x) * (test.y - points[i].y) / (points[j].y-points[i].y) + points[i].x)) {
          result = !result;
         }
      }
      return result;
    }
}

【讨论】:

    猜你喜欢
    • 2017-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    相关资源
    最近更新 更多