2010-02-14 11 views
12

Busco una manera de calcular el área, en píxeles, de una instancia arbitraria de java.awt.geom.Area.Cómo calcular el área de un java.awt.geom.Area?

El fondo: Tengo Shape s en mis aplicaciones que pueden superponerse. Quiero saber cuánto uno Shape se superpone a otro. Los Shape s pueden ser sesgado, girar, etc. Si tuviera una función area(Shape) (o Area), podría usar la intersección de dos Shape s así:

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

qué dobles [] coords = new double [6]; y no se usa otro índice? –

+0

Usted debe ser capaz de extender la fórmula intersección de polígono para Beizer curvas. Luego puede usar iteradores de ruta para obtener áreas casi perfectas para todas las formas/áreas. –

Respuesta

3

Un enfoque sería a fill() cada escala y se transformedShape con un color diferente usando un AlphaComposite adecuado y cuente los píxeles superpuestos en el Raster subyacente.

Addendum 1: El uso de este calculator para ver el efecto de AlphaComposite.Xor muestra que la intersección de dos colores opacos es cero.

Adición 2: Cuenta de píxeles pueden tener problemas de rendimiento; el muestreo puede ayudar. Si cada Shape es razonablemente convexo, puede ser posible estimar la superposición de la relación del área intersect() a la suma de las áreas del Shape s 'getBounds2D(). Por ejemplo,

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(); 
} 

Es posible que deba validar los resultados empíricamente.

+0

Gracias por señalar las opciones de rasterizar parte de la imagen y mirar los valores de muestra reales. – iter

+0

Creo que es más preciso, pero también sugerí una alternativa potencialmente más rápida que puede ser suficiente. – trashgod

11

para encontrar el área de un polígono usando el siguiente fragmento:

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)); 

Aquí n es el número total de vértices y x [i] e y [i] son ​​los coordenadas x e y de un vértice yo. Tenga en cuenta que para este algoritmo funcione, el polígono debe estar cerrada. No funciona en polígonos abiertos.

Puede encontrar alogritos matemáticos relacionados con los polígonos here. Necesita convertirlo a código usted mismo :)

+0

Gracias por el enlace. Este es un enfoque válido, pero no una dirección en la que quiero entrar. 'Shape's puede incluir segmentos de curva y pueden ser composiciones de otras formas.Las matemáticas se ponen demasiado peludas para que pueda seguirlas. – iter

+3

@iter, puede usar un 'getPathIterator (AffineTransform at, double flatness)' para aproximar la curva como un polígono. Además, los constructores del 'Área' descompondrán la forma en componentes que no se intersecan a sí mismos, por lo que este algoritmo funcionará si lo adapta para usar un' PathIterator'. – finnw

+0

Ver http://stackoverflow.com/a/22910330/798223 – GKFX

6

He usado esta clase para aproximar el área de una forma en uno de mis proyectos. Es lento, pero en alta resolución todavía puede ser más rápido que contar píxeles (porque el costo de contar píxeles crece cuadráticamente con la resolución, pero el número de segmentos de línea en el perímetro crece linealmente.)

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

me gustaría comentar si Yo podría. Suraj, el algoritmo es correcto, pero el código debe ser

 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); 

En el último código de vértice no se tiene en cuenta. Sólo una pequeña edición :)

Cuestiones relacionadas