简体   繁体   English

如何计算 java.awt.geom.Area 的面积?

[英]How to calculate the area of a java.awt.geom.Area?

I am looking for a way to calculate the area, in pixels, of an arbitrary instance of java.awt.geom.Area .我正在寻找一种方法来计算java.awt.geom.Area的任意实例的面积(以像素为单位)。

The background: I have Shape s in my applications that may overlap.背景:我的应用程序中有可能重叠的Shape I want to know how much one Shape overlaps another.我想知道一个Shape与另一个Shape重叠了多少。 The Shape s may be skewed, rotated, etc. If I had a function area(Shape) (or Area ), I could use the intersection of two Shape s like so: 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);
}

To find the area of a polygon using the following snippet:要使用以下代码段查找多边形的面积:

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

Here n is the total number of vertices and x[i] and y[i] are the x and y coordinates of a vertex i.这里 n 是顶点的总数,x[i] 和 y[i] 是顶点 i 的 x 和 y 坐标。 Note that for this algorithm to work, the polygon must be closed.请注意,要使该算法起作用,多边形必须是闭合的。 It doesent work on open polygons.它不适用于开放多边形。

You can find mathematical alogrithms related to polygons here .您可以在此处找到与多边形相关的数学算法。 You need to convert it to code yourself:)您需要自己将其转换为代码:)

I've used this class to approximate the area of a shape in one of my projects.我在我的一个项目中使用这个类来近似一个形状的面积。 It's slow but at high resolution it may still be faster than counting pixels (because the cost of counting pixels grows quadratically with resolution, but the number of line segments on the perimeter grows linearly.)它很慢,但在高分辨率下它可能仍然比计算像素更快(因为计算像素的成本与分辨率成二次方增长,但周边线段的数量呈线性增长。)

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

One approach would be to fill() each scaled and transformedShape with a different color using a suitable AlphaComposite and count the overlapping pixels in the underlying Raster .一种方法是使用合适的AlphaComposite用不同的颜色fill()每个缩放和转换的Shape并计算底层Raster的重叠像素。

Addendum 1: Using this calculator to see the effect of AlphaComposite.Xor shows that the intersetion of any two opaque colors is zero.附录 1:使用此计算器查看AlphaComposite.Xor的效果表明,任何两种不透明颜色的交集为零。

Addendum 2: Counting pixels may have performance problems;附录2:计算像素可能有性能问题; sampling may help.抽样可能会有所帮助。 If eachShape is reasonably convex, it may be possible to estimate the overlap from the ratio of the intersect() area to the sum of the areas of theShape s'getBounds2D() .如果每个Shape都是合理的凸面,则可以通过intersect()区域与ShapegetBounds2D()区域总和的比率来估计重叠。 For example,例如,

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

You may need to validate the results empirically.您可能需要凭经验验证结果。

I would comment if I could.如果可以,我会发表评论。 Suraj, your algorithm is correct, but the code should be 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);

In your code last vertice is not taken into account.在您的代码中,不考虑最后一个顶点。 Just a small edit :)只是一个小的编辑:)

The given answer is not accurate , I have found that following solution gives much better results给出的答案不准确,我发现以下解决方案提供了更好的结果

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM