Как объединить два прямоугольника по заданным массивам их координат? - PullRequest
2 голосов
/ 27 мая 2019

Скажем, у меня есть два массива координат (x, y) из двух прямоугольников, например [(0, 0), (0, 1), (2, 1), (2, 0)] и [(1, 0), (1, 2), (3, 2), (3, 0)], как бы я объединил эти два координатных массива в один массив, который представляет результирующий многоугольник?

Это может выглядеть такэто графически:

   _ _
 _|_  |
|_|_|_|

до

   _ _
 _|   |
|_ _ _|

с результирующим массивом [(0, 0), (0, 1), (1, 1), (1, 2), (3, 2), (3, 0)].

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

Для ввода, будет два массива, и этот метод вернет один объединенный массив.

Я просто совершенно не знаю, с чего начать.

Ответы [ 4 ]

1 голос
/ 27 мая 2019

В качестве указателя можно рассмотреть следующее:

Я предполагаю, что каждый массив (r1 и r2) построен так же, как в: [(внизу слева) (вверху слева) (вверху справа) (вверху слева)]

Если есть какие-либо перекрытия прямоугольников (тела, а не только углы), то результатом может быть от четырех до двенадцати различных координат внутри вашего нового массива.

Сначала мы проверяем, какая пара находится дальше всего, если она есть, мы добавляем ее в новый массив. Сравнение координаты X нижнего левого угла r1 с координатой X нижнего левого угла r2 должно быть достаточным. Если НЕ и левая сторона обоих прямоугольников находится в одной и той же координате X, мы добавляем нижнюю левую с более низким значением Y и верхнюю левую с большим значением Y. Эта логика может быть применена ко всем четырем сторонам.

В нашем случае, например, самая дальняя левая сторона, нам все еще нужно проверить, перекрывается ли меньшая левая сторона сверху или снизу. Мы делаем это, просто вычитая Y верхнего левого r1 из значения Y верхнего левого r2. Если есть разница (то есть меньшая левая сторона выше, мы добавляем верхние левые координаты R2 в массив вместе с (r2 X, r1 Y). Аналогичная логика должна применяться для всех сторон в случае, если есть больше крайняя сторона.

Таким образом, общий поток для этого будет

  1. Проверьте самые внешние края. Они могут быть добавлены без каких-либо изменений. Для этого должно быть достаточно простого однокоординатного сравнения. Если есть внешний край, следуйте см. (2), иначе см. (3)
  2. Проверьте, больше ли НЕ самый наружный край в другом направлении. Так, например, в случае левой проверки, предположим, что r1 еще левее. Проверьте, находится ли верхний левый угол r2 выше верхнего левого угла r1. Если это так, добавьте верхний левый угол r2 вместе с новой координатой (r2 верхний левый x | r1 верхний левый Y). Имейте в виду, что, например, в этой ситуации левый край r2 может быть как: верхний, так и нижний!
  3. Поскольку оба ребра находятся на одном уровне (например, одно и то же значение X), нам нужно увидеть, например, внизу слева дальше вниз, возьмите его и сложите вместе с верхним левым углом вверх.

A small visualization of single cases.

0 голосов
/ 27 мая 2019

Существует много степеней свободы в отношении подходов и фактической реализации здесь.Некоторые важные вопросы, которые нужно рассмотреть, просто из головы:

  • Координаты всегда целые?
  • Всегда ли входные фигуры всегда (выровнены по оси) прямоугольниками?
  • Всегда ли прямоугольники перекрываются?
  • Всегда ли точки находятся в разных координатах?
  • Разве края никогда не равны?
  • ...

В некоторых случаях (если на первые три вопроса ответ «Да»), вы, вероятно, могли бы пойти на технически очень простой подход: просто рассмотрите весьвведите как «сетку», где прямоугольники определяют ячейки сетки, которые «заполнены», и, в конце, возвращают границу заполненной области.

Если ответом на один из них может быть «Нет», то вы открываете банку с червями со многими, многими тонкостями.

К счастью, люди в Sun / Oracle отлично с этим справились, и может все же быть простым решением даже для очень сложных задач: вы можете преобразоватьввод в фигуры, а затем используйте метод Area#add для вычисления объединенной фигуры.

Это реализовано в этом примере.Но обратите внимание, что это не очень эффективно по сравнению, скажем, с сеточным подходом, который можно использовать для более простых случаев .И это все еще оставляет открытым вопрос о том, что должно случиться с неперекрывающимися прямоугольниками.Однако, по крайней мере для заданных входных данных, результат является ожидаемым:

import java.awt.Point;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Path2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class RectangleMerge {

    public static void main(String[] args) {
        List<Point2D> pointsA = Arrays.asList(new Point(0, 0), new Point(0, 1), new Point(2, 1), new Point(2, 0));
        List<Point2D> pointsB = Arrays.asList(new Point(1, 0), new Point(1, 2), new Point(3, 2), new Point(3, 0));

        System.out.println(merge(pointsA, pointsB));
    }

    private static List<Point2D> merge(List<? extends Point2D> pointsA, List<? extends Point2D> pointsB) {
        Area aa = new Area(toShape(pointsA));
        aa.add(new Area(toShape(pointsB)));
        return toPoints(aa);
    }

    private static Shape toShape(List<? extends Point2D> points) {
        Path2D path = new Path2D.Double();
        for (int i = 0; i < points.size(); i++) {
            Point2D p = points.get(i);
            if (i == 0) {
                path.moveTo(p.getX(), p.getY());
            } else {
                path.lineTo(p.getX(), p.getY());
            }
        }
        path.closePath();
        return path;
    }

    private static List<Point2D> toPoints(Shape shape) {
        List<Point2D> result = new ArrayList<Point2D>();
        PathIterator pi = shape.getPathIterator(null, 0.0);
        double[] coords = new double[6];
        while (!pi.isDone()) {
            int segment = pi.currentSegment(coords);
            switch (segment) {
            case PathIterator.SEG_MOVETO:
            case PathIterator.SEG_LINETO:
                result.add(new Point2D.Double(coords[0], coords[1]));
                break;
            }
            pi.next();
        }
        return result;
    }

}
0 голосов
/ 27 мая 2019

Сначала убедитесь, что левый нижний угол первого прямоугольника не находится внутри другого прямоугольника.Если это так, поменяйте их местами.Углы могут перекрываться, или угол может быть на стороне другого прямоугольника, это нормально.

Затем начните идти вдоль левого прямоугольника против часовой стрелки, так что вправо на нижней стороне.проверьте, закончите ли вы, потому что вы:

  1. достигли конца первым
  2. сначала попали в левую стену другого прямоугольника

Если вы достигли конца, продолжайте идти вверх по правому краю первого прямоугольника.Если вы нажмете другой прямоугольник, идите вниз по левой стене другого прямоугольника.

Повторяйте, пока снова не нагреете левый нижний угол первого прямоугольника.В каждой точке вам нужно помнить: в какую сторону вы движетесь / на какую сторону идете (поскольку вы всегда движетесь против часовой стрелки, одно легко вычисляется из другого) и на каком прямоугольнике вы находитесь.

Если вы совсем не попадаете в другой прямоугольник во время прогулки, это означает, что прямоугольники не соприкасаются, или второй прямоугольник находится внутри первого.

Обязательно продумайте неравенствачто вы будете использовать, например:

 ______
|  |_| |
|      |
|______|

Должны ли эти два прямоугольника слиться в один или шестиугольник с 3 линиями по прямой линии?Или это:

 _
|_|_
  |_|

Be 2 разных прямоугольника или 1 8-многоугольник с 2 одинаковыми точками?

0 голосов
/ 27 мая 2019

(Никогда не больно упорядочивать вещи (но здесь это может не помочь): упорядочить точки в положительном порядке, скажем, начиная с левого верхнего края.)

Для слияния (a.topx .. a.bottomx) и (b.topx .. b.bottomx) должны перекрываться, то же самое для y.

Внешний прямоугольник - external.topx = min (a.topx, b.topx) и т. д.

X-координаты, возможно случайные, являются external.topx, a.topx, b.topx, outer.bottom.x.Теперь вы найдете одну границу многоугольника.И так далее.

Соединительные внутренние ребра тривиальны.

Имейте в виду, что существует множество форм, но обобщенной является:

...._____.....
:___|    |___:
|___      ___|
:...|____|...:

Независимо от того, желаете ли выболее общий алгоритм объединения любого многоугольника - вопрос, так как добавление третьего прямоугольника станет совершенно другим случаем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...