【问题标题】:How to calculate the area of a java.awt.geom.Area?如何计算 java.awt.geom.Area 的面积?
【发布时间】:2010-02-14 23:23:32
【问题描述】:

我正在寻找一种方法来计算java.awt.geom.Area 任意实例的面积(以像素为单位)。

背景:我的应用程序中有Shapes,它们可能会重叠。我想知道一个Shape 与另一个重叠多少。 Shapes 可能会倾斜、旋转等。如果我有一个函数area(Shape)(或Area),我可以像这样使用两个Shapes 的交集:

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

【问题讨论】:

  • 为什么 double[] coords = new double[6];并且没有使用其他索引?
  • 您应该能够将多边形相交公式扩展到贝泽曲线。然后,您可以使用路径迭代器为所有形状/区域获得近乎完美的区域。

标签: java swing geometry


【解决方案1】:

使用以下 sn-p 求多边形的面积:

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

这里 n 是顶点的总数,x[i] 和 y[i] 是顶点 i 的 x 和 y 坐标。 请注意,要使此算法起作用,必须关闭多边形。它不适用于开放的多边形。

您可以找到与多边形相关的数学算法here。您需要自己将其转换为代码:)

【讨论】:

  • 感谢您的链接。这是一种有效的方法,但不是我想要的方向。Shapes 可能包括曲线段,也可能是其他形状的组合。数学太复杂了,我无法理解。
  • @iter,您可以使用getPathIterator(AffineTransform at, double flatness) 将曲线近似为多边形。此外,Area 构造函数会将形状分解为非自相交的组件,因此如果您将其调整为使用 PathIterator,此算法将起作用。
【解决方案2】:

我在我的一个项目中使用这个类来近似形状的面积。它很慢,但在高分辨率下它可能仍然比计算像素快(因为计算像素的成本随分辨率呈二次方增长,但周长上的线段数量呈线性增长。)

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

【讨论】:

    【解决方案3】:

    一种方法是使用合适的AlphaCompositefill() 每个缩放和transformed Shape 使用不同的颜色,并计算底层Raster 中的重叠像素。

    附录1:用这个calculatorAlphaComposite.Xor的效果,显示任意两种不透明颜色的交集为零。

    附录2:计数像素可能存在性能问题;采样可能会有所帮助。如果每个Shape 都是合理凸的,则可以根据intersect() 面积与Shapes'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();
    }
    

    您可能需要凭经验验证结果。

    【讨论】:

    • 感谢您指出光栅化部分图像和查看实际样本值的选项。
    • 我认为它更准确,但我也建议了一个可能更快的替代方案,可能就足够了。
    【解决方案4】:

    如果可以的话,我会发表评论。 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);
    

    在您的代码中,最后一个顶点未被考虑在内。只是一个小编辑:)

    【讨论】:

      【解决方案5】:

      给出的答案不准确,我发现关注solution 会得到更好的结果

      private int calcAreaSize(Area area){
          int sum = 0;
          float xBegin=0, yBegin=0, xPrev=0, yPrev=0, coords[] = new float[6];
          for (PathIterator iterator1 = area.getPathIterator(null, 0.1); !iterator1.isDone(); iterator1.next()){
              switch (iterator1.currentSegment(coords))
              {
                  case PathIterator.SEG_MOVETO:
                      xBegin = coords[0]; yBegin = coords[1];
                      break;
                  case PathIterator.SEG_LINETO:
                      // the well-known trapez-formula
                      sum += (coords[0] - xPrev) * (coords[1] + yPrev) / 2.0;
                      break;
                  case PathIterator.SEG_CLOSE:
                      sum += (xBegin - xPrev) * (yBegin + yPrev) / 2.0;
                      break;
                  default:
                      // curved segments cannot occur, because we have a flattened ath
                      throw new InternalError();
              }
              xPrev = coords[0]; yPrev = coords[1];
          }
          return sum;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-12
        • 2020-09-15
        • 1970-01-01
        • 1970-01-01
        • 2016-12-13
        • 2015-01-16
        • 2011-06-07
        相关资源
        最近更新 更多