1

我正在尝试使用 PathIterator 来计算任何 Shape 对象的中心,以便可以计算弯曲路径,但是在找到标准 1x1 矩形的中心后,我的 getCenter() 方法会返回该点:

Point2D.Double[0.3333333333333333, 0.3333333333333333]

我的 getCenter() 方法:

shape = new Rectangle2D.Double(0, 0, 1, 1);


public Point2D.Double getCenter()
        {
            ArrayList<Point2D.Double> points = new ArrayList<Point2D.Double>();
            double[] arr = new double[6];
            for(PathIterator pi = shape.getPathIterator(null); !pi.isDone(); pi.next())
            {
                pi.currentSegment(arr);
                points.add(new Point2D.Double(arr[0], arr[1]));
            }

            double cX = 0;
            double cY = 0;
            for(Point2D.Double p : points)
            {
                cX += p.x;
                cY += p.y;
            }
                    System.out.println(points.toString());
            return new Point2D.Double(cX / points.size(), cY / points.size());
        }

我发现在打印 points.toString() 时,我在控制台中得到了这个:

[Point2D.Double[0.0, 0.0], Point2D.Double[1.0, 0.0], Point2D.Double[1.0, 1.0], Point2D.Double[0.0, 1.0], Point2D.Double[0.0, 0.0], Point2D.Double[0.0, 0.0]]

我注意到点数组中有六个条目,而不是我期望的四个,因为输入的 Shape 对象是 Rectangle2D.Double(0, 0, 1, 1)。显然,它对点 (0, 0) 的解释比我想要的多两倍,我对为什么会这样感到困惑。它是 PathIterator.isDone() 方法的结果吗?我使用不正确吗?如果 PathIterator 不能解决我的问题怎么办?

4

3 回答 3

0

PathIterator定义了不同类型的段,你应该注意这个事实。在您的示例中,您得到 6 个段,因为它还返回 SEG_MOVETO 段,它定义了子路径的开始,以及 SEG_CLOSE 在子路径的结尾。如果您只想获取形状线条的端点,您应该像这样更改代码:

    for(PathIterator pi = shape.getPathIterator(null); !pi.isDone(); pi.next())
    {
        if(pi.currentSegment(arr) == PathIterator.SEG_LINETO) {
            points.add(new Point2D.Double(arr[0], arr[1]));
        }
    }
于 2014-02-23T21:17:08.677 回答
0

我不确定您使用不正确,但您没有考虑PathIterator的一个方面。PathIterator 与其说是几何形状,不如说是绘制时应该采用的路径。所以它的点也代表了“笔”应该走的路径类型。例如,对于 Rectangle,路径包含以下部分:

  1. SEG_MOVETO
  2. SEG_LINETO
  3. SEG_LINETO
  4. SEG_LINETO
  5. SEG_LINETO
  6. SEG_CLOSE

因为显然路径应该:

  • 从笔之前的任何地方移动,而不是绘图。
  • 将这条路径与笔接下来绘制的任何内容隔离开。

段的类型是的返回值currentSegment。如果您只想捕获多边形上的点,您可以检查“line to”段:

if(pi.currentSegment(arr) == PathIterator.SEG_LINETO) {
    points.add(new Point2D.Double(arr[0], arr[1]));
}

这适用于像矩形这样的简单多边形。对于给定的 Rectangle,它将返回 [0.5, 0.5] 我假设您感兴趣的结果。

另一方面,有些形状不是多边形,所以我会小心这种方法。

于 2014-02-23T21:17:24.680 回答
0

正如已经指出的那样,PathIterator 返回不同类型的段。当只考虑SEG_LINETO中涉及的点时,应该已经获得了满意的结果。但是,考虑到其他形状也可能存在 SEG_QUADTO 和 SEG_CUBICTO。这些可以通过使用扁平化的 PathIterator 轻松避免:当您使用以下方法创建 PathIterator 时

PathIterator pi = shape.getPathIterator(null, flatness);

具有适当的平整度,则它将仅包含直线段。

import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

public class ShapeCenter
{
    public static void main(String[] args)
    {
        System.out.println(computeCenter(new Ellipse2D.Double(-10,-10,20,20)));
        System.out.println(computeCenter(new Rectangle2D.Double(0,0,1,1)));
    }

    public static Point2D computeCenter(Shape shape)
    {
        final double flatness = 0.1;
        PathIterator pi = shape.getPathIterator(null, flatness);
        double coords[] = new double[6];
        double sumX = 0;
        double sumY = 0;
        int numPoints = 0;
        while (!pi.isDone())
        {
            int s = pi.currentSegment(coords);
            switch (s)
            {
                case PathIterator.SEG_MOVETO:
                    // Ignore
                    break;

                case PathIterator.SEG_LINETO:
                    sumX += coords[0]; 
                    sumY += coords[1]; 
                    numPoints++;
                    break;

                case PathIterator.SEG_CLOSE:
                    // Ignore
                    break;

                case PathIterator.SEG_QUADTO:
                    throw new AssertionError(
                        "SEG_QUADTO in flattening path iterator");
                case PathIterator.SEG_CUBICTO:
                    throw new AssertionError(
                        "SEG_CUBICTO in flattening path iterator");
            }
            pi.next();
        }
        double x = sumX / numPoints;
        double y = sumY / numPoints;
        return new Point2D.Double(x,y);
    }

}
于 2014-02-23T21:30:38.653 回答