2010-02-14 8 views
12

Я ищу способ вычисления площади в пикселях произвольного экземпляра java.awt.geom.Area.Как рассчитать площадь java.awt.geom.Area?

Фон: У меня есть Shape s в моих приложениях, которые могут перекрываться. Я хочу знать, сколько один Shape перекрывает другой. В Shape ы может быть искажен, поворачивается и т.д. Если я имел функцию area(Shape) (или Area), я мог бы использовать пересечение двух Shape с примерно так:

double fractionObscured(Shape bottom, Shape top) { 
    Area intersection = new Area(bottom); 
    intersection.intersect(new Area(top)); 
    return area(intersection)/area(bottom); 
} 
+0

почему double [] coords = new double [6]; и не используется другой индекс? – 2012-03-15 07:11:39

+0

Вы должны иметь возможность расширить формулу пересечения многоугольника на кривые бисера. Затем вы можете использовать итераторы пути для получения почти идеальных областей для всех фигур/областей. –

ответ

3

Один подход заключается в fill() каждые масштабированная и transformedShape с другим цветом, используя подходящий AlphaComposite и подсчитайте перекрывающиеся пиксели в базовом Raster.

Приложение 1: Используя этот calculator, чтобы увидеть эффект AlphaComposite.Xor, показано, что пересечение любых двух непрозрачных цветов равно нулю.

Приложение 2: Подсчет пикселей может иметь проблемы с производительностью; выборка может помочь. Если каждый Shape является достаточно выпуклым, может быть возможно оценить перекрытие от отношения площади intersect() к сумме площадей Shape s 'getBounds2D(). Например,

Shape s1, s2 ... 
Rectangle2D r1 = s1.getBounds2D(); 
Rectangle2D r2 = s2.getBounds2D(); 
Rectangle2D r3 = new Rectangle2D.Double(); 
Rectangle2D.intersect(r1, r2, r3); 
double overlap = area(r3)/(area(r1) + area(r2)); 
... 
private double area(Rectangle2D r) { 
    return r.getWidth() * r.getHeight(); 
} 

Возможно, вам нужно будет скорректировать результаты эмпирически.

+0

Благодарим вас за то, что вы указали варианты растеризационной части изображения и посмотрели фактические значения выборки. – iter

+0

Я думаю, что это более точно, но я также предложил потенциально более быструю альтернативу, которая может быть достаточной. – trashgod

11

Чтобы найти площадь многоугольника, используя следующий фрагмент кода:

int sum = 0; 
for (int i = 0; i < n -1; i++) 
{ 
    sum = sum + x[i]*y[i+1] - y[i]*x[i+1]; 
} 
// (sum/2) is your area. 
System.out.println("The area is : " + (sum/2)); 

Здесь п общее число вершин и х [I] и у [I] являются х и у координаты вершины я. Обратите внимание, что для того, чтобы этот алгоритм работал, многоугольник должен быть закрыт. Это делает работу над открытыми полигонами.

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

+0

Спасибо за ссылку. Это действительный подход, но не направление, в которое я хочу войти. 'Shape's может включать в себя сегменты кривой и может быть композициями других форм.Для меня математика становится слишком волосатой. – iter

+3

@iter, вы можете использовать 'getPathIterator (AffineTransform at, double flatness)', чтобы аппроксимировать кривую как многоугольник. Кроме того, конструкторы 'Area' будут разлагать фигуру на несамопересекающиеся компоненты, поэтому этот алгоритм будет работать, если вы адаптируете его для использования« PathIterator ». – finnw

+0

См. Http://stackoverflow.com/a/22910330/798223 – GKFX

6

Я использовал этот класс, чтобы приблизиться к области формы в одном из моих проектов. Это медленно, но при высоком разрешении он по-прежнему может быть быстрее, чем подсчет пикселей (поскольку стоимость подсчета пикселей растет квадратично с разрешением, но количество отрезков по периметру растет линейно.)

import static java.lang.Double.NaN; 

import java.awt.geom.AffineTransform; 
import java.awt.geom.Area; 
import java.awt.geom.FlatteningPathIterator; 
import java.awt.geom.Line2D; 
import java.awt.geom.PathIterator; 

public abstract class Areas { 
    public static double approxArea(Area area, double flatness, int limit) { 
     PathIterator i = 
      new FlatteningPathIterator(area.getPathIterator(identity), 
             flatness, 
             limit); 
     return approxArea(i); 
    } 

    public static double approxArea(Area area, double flatness) { 
     PathIterator i = area.getPathIterator(identity, flatness); 
     return approxArea(i); 
    } 

    public static double approxArea(PathIterator i) { 
     double a = 0.0; 
     double[] coords = new double[6]; 
     double startX = NaN, startY = NaN; 
     Line2D segment = new Line2D.Double(NaN, NaN, NaN, NaN); 
     while (! i.isDone()) { 
      int segType = i.currentSegment(coords); 
      double x = coords[0], y = coords[1]; 
      switch (segType) { 
      case PathIterator.SEG_CLOSE: 
       segment.setLine(segment.getX2(), segment.getY2(), startX, startY); 
       a += hexArea(segment); 
       startX = startY = NaN; 
       segment.setLine(NaN, NaN, NaN, NaN); 
       break; 
      case PathIterator.SEG_LINETO: 
       segment.setLine(segment.getX2(), segment.getY2(), x, y); 
       a += hexArea(segment); 
       break; 
      case PathIterator.SEG_MOVETO: 
       startX = x; 
       startY = y; 
       segment.setLine(NaN, NaN, x, y); 
       break; 
      default: 
       throw new IllegalArgumentException("PathIterator contains curved segments"); 
      } 
      i.next(); 
     } 
     if (Double.isNaN(a)) { 
      throw new IllegalArgumentException("PathIterator contains an open path"); 
     } else { 
      return 0.5 * Math.abs(a); 
     } 
    } 

    private static double hexArea(Line2D seg) { 
     return seg.getX1() * seg.getY2() - seg.getX2() * seg.getY1(); 
    } 

    private static final AffineTransform identity = 
     AffineTransform.getQuadrantRotateInstance(0); 
} 
2

Я хотел бы прокомментировать, если Я мог бы. Suraj, ваш алгоритм верен, но код должен быть

 int sum = 0; 
     for (int i = 0; i < npoints ; i++) 
     { 
      sum = sum + Xs[i]*Ys[(i+1)%npoints] - Ys[i]*Xs[(i+1)%npoints]; 
     } 

     return Math.abs(sum/2); 

В вашем коде последняя вершина не учитывается. Просто небольшое редактирование:

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