Как рассчитать площадь java.awt.geom.Area?
Я ищу способ вычисления площади в пикселях произвольного экземпляра java.awt.geom.Area
.
Фон: у меня есть Shape
в моих приложениях, которые могут перекрываться. Я хочу знать, насколько один 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);
}
Ответы
Ответ 1
Один подход заключается в fill()
каждый масштабированный и transformed Shape
с другим цветом, используя подходящий AlphaComposite
и подсчитайте перекрывающиеся пиксели в базовом Raster
.
Добавление 1: Используя этот калькулятор, чтобы увидеть эффект 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();
}
Вам может потребоваться проверить результаты эмпирически.
Ответ 2
Чтобы найти область многоугольника, используя следующий фрагмент:
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] - координаты x и y вершины i.
Обратите внимание, что для того, чтобы этот алгоритм работал, многоугольник должен быть закрыт. Он выполняет работу над открытыми многоугольниками.
Вы можете найти математические алограммы, связанные с полигонами здесь. Вам нужно преобразовать его в код самостоятельно:)
Ответ 3
Я использовал этот класс для аппроксимации области фигуры в одном из моих проектов. Он медленный, но с высоким разрешением он все же может быть быстрее, чем подсчет пикселей (потому что стоимость подсчета пикселей растет квадратично с разрешением, но количество сегментов линии по периметру растет линейно.)
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);
}
Ответ 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);
В вашем коде последняя вершина не учитывается. Просто небольшое редактирование:)