Java- точка пересечения многоугольника и линии

Есть ли какая-нибудь функция, которая даст мне точку пересечения Polygon и Line2D?

У меня есть многоугольник и сегмент линии, которые, как я знаю, пересекаются. Мне нужно фактическое значение точки пересечения, а не логический ответ.


person bryan    schedule 03.03.2011    source источник
comment
Вероятно, мне следует добавить, что я знаю, что он пересекается ровно в 1 месте, потому что я знаю, что одна точка находится снаружи, а другая внутри многоугольника. Но я не знаю, какой отрезок многоугольника он пересекает   -  person bryan    schedule 03.03.2011


Ответы (5)


А, вот и ты. Интересными методами являются getIntersections и getIntersection. Первый выполняет синтаксический анализ всех сегментов полигона и проверяет наличие пересечений, второй выполняет фактический расчет. Имейте в виду, что расчет может быть серьезно оптимизирован и не проверяет деление на 0. Это также будет работать только для полигонов. Его можно адаптировать для работы с другими формами, если ввести вычисления для кубических и квадратичных кривых. Предполагается, что вместо Line2D.Float используется Line2D.Double. Набор используется, чтобы избежать дублирования точек (могут возникнуть на пересечениях углов многоугольника).

Пожалуйста, не используйте это без тщательного тестирования, так как я только что быстро взломал его и не уверен, что он полностью исправен.

package quickpolygontest;

import java.awt.Polygon;
import java.awt.geom.Line2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class Main {

    public static void main(String[] args) throws Exception {

        final Polygon poly = new Polygon(new int[]{1,2,2,1}, new int[]{1,1,2,2}, 4);
        final Line2D.Double line = new Line2D.Double(2.5, 1.3, 1.3, 2.5);
        final Set<Point2D> intersections = getIntersections(poly, line);
        for(Iterator<Point2D> it = intersections.iterator(); it.hasNext();) {
            final Point2D point = it.next();
            System.out.println("Intersection: " + point.toString());
        }

    }

    public static Set<Point2D> getIntersections(final Polygon poly, final Line2D.Double line) throws Exception {

        final PathIterator polyIt = poly.getPathIterator(null); //Getting an iterator along the polygon path
        final double[] coords = new double[6]; //Double array with length 6 needed by iterator
        final double[] firstCoords = new double[2]; //First point (needed for closing polygon path)
        final double[] lastCoords = new double[2]; //Previously visited point
        final Set<Point2D> intersections = new HashSet<Point2D>(); //List to hold found intersections
        polyIt.currentSegment(firstCoords); //Getting the first coordinate pair
        lastCoords[0] = firstCoords[0]; //Priming the previous coordinate pair
        lastCoords[1] = firstCoords[1];
        polyIt.next();
        while(!polyIt.isDone()) {
            final int type = polyIt.currentSegment(coords);
            switch(type) {
                case PathIterator.SEG_LINETO : {
                    final Line2D.Double currentLine = new Line2D.Double(lastCoords[0], lastCoords[1], coords[0], coords[1]);
                    if(currentLine.intersectsLine(line))
                        intersections.add(getIntersection(currentLine, line));
                    lastCoords[0] = coords[0];
                    lastCoords[1] = coords[1];
                    break;
                }
                case PathIterator.SEG_CLOSE : {
                    final Line2D.Double currentLine = new Line2D.Double(coords[0], coords[1], firstCoords[0], firstCoords[1]);
                    if(currentLine.intersectsLine(line))
                        intersections.add(getIntersection(currentLine, line));
                    break;
                }
                default : {
                    throw new Exception("Unsupported PathIterator segment type.");
                }
            }
            polyIt.next();
        }
        return intersections;

    }

    public static Point2D getIntersection(final Line2D.Double line1, final Line2D.Double line2) {

        final double x1,y1, x2,y2, x3,y3, x4,y4;
        x1 = line1.x1; y1 = line1.y1; x2 = line1.x2; y2 = line1.y2;
        x3 = line2.x1; y3 = line2.y1; x4 = line2.x2; y4 = line2.y2;
        final double x = (
                (x2 - x1)*(x3*y4 - x4*y3) - (x4 - x3)*(x1*y2 - x2*y1)
                ) /
                (
                (x1 - x2)*(y3 - y4) - (y1 - y2)*(x3 - x4)
                );
        final double y = (
                (y3 - y4)*(x1*y2 - x2*y1) - (y1 - y2)*(x3*y4 - x4*y3)
                ) /
                (
                (x1 - x2)*(y3 - y4) - (y1 - y2)*(x3 - x4)
                );

        return new Point2D.Double(x, y);

    }

}
person G_H    schedule 03.03.2011

Существует java.awt.geom.Area.intersect(Area), использующий конструктор Area(Shape) с вашим многоугольником, и передача вашего Line2D в качестве области для пересечения даст вам область, которая пересекается.

person initialZero    schedule 03.03.2011

С большим успехом я использовал этот подход:

Area a = new Area(shape1);
Area b = new Area(shape2);
b.intersect(a);
if (!b.isEmpty()) {
  //Shapes have non-empty intersection, so do you actions.
  //In case of need, actual intersection is in Area b. (its destructive operation)
}
person ArcanisCz    schedule 13.11.2012

Вы должны иметь в виду, что они могут пересекаться в нескольких местах.

Назовем отрезок многоугольника P, а реальный отрезок L.

Находим наклон каждой линии (наклон равен м)

ml = (ly1-ly2) / (lx1-lx2);
mp = (ply-pl2) / (px1-px2);

Найдите точку пересечения y каждой строки

// y = mx+b where b is y-intercept
bl = ly1 - (ml*lx1);
bp = py1 - (pl*px1);

Вы можете решить значение x с помощью:

x = (bp - bl) / (ml - mp)

Затем подставьте этот X в одно из уравнений, чтобы получить Y

y = ml * x + bl

Вот реализованная версия алгоритма

class pointtest {

    static float[] intersect(float lx1, float ly1, float lx2, float ly2,
                           float px1, float py1, float px2, float py2) {
        // calc slope
        float ml = (ly1-ly2) / (lx1-lx2);
        float mp = (py1-py2) / (px1-px2);       

        // calc intercept        
        float bl = ly1 - (ml*lx1);
        float bp = py1 - (mp*px1);  

        float x = (bp - bl) / (ml - mp);
        float y = ml * x + bl;

        return new float[]{x,y};
    }

    public static void main(String[] args) {

        float[] coords = intersect(1,1,5,5,1,4,5,3);
        System.out.println(coords[0] + " " + coords[1]);

    }
}

и результаты:

3.4 3.4
person corsiKa    schedule 03.03.2011
comment
Я должен указать, что есть некоторые условия, которые здесь не рассматриваются. Что происходит, когда линии совпадают? Что происходит, когда линии не пересекаются (равный наклон)? Что произойдет, если пересечение произойдет за пределами сегмента прямой? Что, если один из них имеет нулевой наклон? Есть несколько особых случаев, оставленных читателю в качестве упражнения. - person corsiKa; 03.03.2011

Если вы не ограничены в использовании объектов Polygon и Line2D, я бы рекомендовал использовать JTS.

  • Создайте геометрию LinearRing (ваш полигон).
  • Создайте геометрию LineString.
  • Создайте точки пересечения, используя пересечение.

Простой пример кода:

// create ring: P1(0,0) - P2(0,10) - P3(10,10) - P4(0,10)
LinearRing lr = new GeometryFactory().createLinearRing(new Coordinate[]{new Coordinate(0,0), new Coordinate(0,10), new Coordinate(10,10), new Coordinate(10,0), new Coordinate(0,0)});
// create line: P5(5, -1) - P6(5, 11) -> crossing the ring vertically in the middle
LineString ls = new GeometryFactory().createLineString(new Coordinate[]{new Coordinate(5,-1), new Coordinate(5,11)});
// calculate intersection points
Geometry intersectionPoints = lr.intersection(ls);
// simple output of points
for(Coordinate c : intersectionPoints.getCoordinates()){
    System.out.println(c.toString());
}

Результат:

(5.0, 0.0, NaN)
(5.0, 10.0, NaN)
person Lars    schedule 10.07.2016