2014-12-13 3 views
2

Можно ли проверить столкновение с линией, используя объект Area?Проверка столкновений с линией и прямоугольником

В настоящее время, как я делаю это не работает:

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

import java.awt.Rectangle; 
import java.awt.geom.Area; 
import java.awt.geom.Line2D; 

public class collision { 

public static void main(String[] args) { 

    Area area1 = new Area(new Rectangle(0, 0, 100, 100)); 
    Area area2 = new Area(new Line2D.Double(0, 0, 100, 100)); 

    System.out.println(isColliding(area1, area2)); 
} 

public static boolean isColliding(Area area1, Area area2) { 
    if (area2 != null) { 
     Area collide1 = new Area(area1); 
     collide1.subtract(area2); 
     if (!collide1.equals(area1)) { 
      return true; 
     } 
    } 

    return false; 

} 

} 
+0

Имея в виду, что Line2D действительно только очень тонкий прямоугольник, вы не могли бы использовать это: https://docs.oracle.com/javase/7/docs/api/java/awt/ geom/Area.html # intersects (java.awt.geom.Rectangle2D) – Kon

+0

Попытайтесь, я не знал, что Line2D был прямоугольником, учитывая, что он повернут (справа?) –

+0

@Kon Вы уверены, что 'Line2D' является прямоугольник - т.е. он имеет такое же поведение, как и «Rectangle2D»? Или вы говорите в общем смысле? – ajb

ответ

1

Я смог решить эту проблему, выполнив рекурсивную функцию, которая проверяет точки вдоль вещи. Чем выше вы задаете глубину, тем более точно она будет проверяться, но займет больше времени. Я использую 10 в качестве моей глубины (которая, я считаю, проверяет 2047 точек вдоль линии), и я не столкнулся с потерей производительности. Если ваш объект Area не содержит действительно тонких деталей, я не думаю, что вам понадобится больше, чем это.

Кто-то не стесняйтесь комментировать и пересмотреть свой метод, если вы считаете, что вы можете улучшить его в любом случае :)

Благодаря AJB его предложению с помощью PathIterator, который дал мне идею, чтобы проверить точки вдоль линии ,

public static boolean findPoints(Area area1, Line2D line1, int depth) { 

    Point p1 = new Point((int) (line1.getX2() + line1.getX1())/2, 
      (int) (line1.getY2() + line1.getY1())/2); 

    if (depth == 0) { 
     return false; 
    } 

    pointMiddle = new Point(p1); 
    if (area1.contains(p1)) { 
     return true; 

    } else { 
     return findPoints(area1, new Line2D.Double(p1, line1.getP2()), 
       depth - 1) 
       || findPoints(area1, new Line2D.Double(line1.getP1(), p1), 
         depth - 1); 
    } 

} 
0

Если, как вы говорите, в комментариях, вы знаете, что вы всегда будете проверки Line2D и Rectangle для столкновения, вы можете использовать intersects метод Line2D (см javadoc):

public static void main(String[] args) { 

    Rectangle rect1 = new Rectangle(0, 0, 100, 100); 
    Line2D line2 = new Line2D.Double(0, 0, 100, 100); 

    System.out.println(isColliding(rect1, line2)); 
} 

public static boolean isColliding(Rectangle2D rect1, Line2D line2) { 
    if (line2 != null) { 
     return line2.intersects(rect1); 
    } 
    return false;  
} 

Испытание, если линия сталкивается с более общим Area, сложнее; Я не думаю, что для этого есть метод в библиотеке. Если Area создан из прямоугольников, вы можете попробовать сохранить массив (или List) объектов Rectangle и проверить, пересекается ли линия с любым из них. Другой подход. Вы можете попробовать использовать метод containsArea, который проверяет, содержит ли область точку. Если либо Конечная точка Line2D содержится в Area, то линия и область сталкиваются. Если обе конечные точки находятся за пределами области, но область состоит из прямых линий (area.isPolygonal()), вы можете извлечь каждый сегмент линии из многоугольника и проверить, пересекает ли линия каждый сегмент линии. Вы можете сделать это с помощью area.getPathIterator(null), а затем использовать что-то вроде этого на полученном пути итератора:

double[] coords = new double[6]; 
double moveX, moveY, prevX, prevY, newX, newY; 
while (!pathIterator.isDone()) { 
    switch (pathIterator.currentSegment(coords)) { 
     case PathIterator.SEG_MOVETO: 
      moveX = coords[0]; moveY = coords[1]; 
      prevX = moveX; prevY = moveY; 
      break; 
     case PathIterator.SEG_LINETO: 
      newX = coords[0]; newY = coords[1]; 
      if ([line2 intersects the line from (prevX,prevY) to (newX,newY)]) { 
       return true; 
      } 
      prevX = newX; prevY = newY; 
      break; 
     case PathIterator.SEG_QUADTO: 
     case PathIterator.SEG_CUBICTO: 
      throw new RuntimeException("What is a curve doing in my rectangle?"); 
     case PathIterator.SEG_CLOSE: 
      // go back to the last SEG_MOVETO point, usually the first point 
      if ([line2 intersects the line from (prevX,prevY) to (moveX,moveY)]) { 
       return true; 
      } 
      prevX = newX; prevY = newY; 
      break; 
    } 
} 

Есть методы в Line2D, чтобы проверить, пересекает ли отрезок другой.

Примечание: Я не тестировал это вообще. Надеюсь это работает.

+0

Мне не удалось заставить это работать. Я никогда раньше не работал с PathIterator, так что, возможно, поэтому. Я оставлю это здесь, если кто-то еще сможет подтвердить, что это работает. Я смог решить свою проблему, выполнив рекурсивную функцию для проверки точек вдоль линии и использования метода .contains (Point p), который может быть вызван объектом Area. –

+0

@SamBurns Ну, как я уже сказал, я не тестировал его. Мне нужно попробовать, когда я смогу найти время, и если я смогу заставить его работать, я отправлю более полный ответ. Таким образом, вы разделили линию на некоторое количество небольших сегментов и проверили каждую точку? Это должно работать в большинстве случаев - у вас должен быть многоугольник с чрезвычайно узкой частью, чтобы сделать этот подход неудачным. Я тоже думал об этом подходе, но я думал, что подход PathIterator будет быстрее. – ajb

+0

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

Смежные вопросы