有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java PathIterator如何准确计算形状对象的中心?

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

Point2D.Double[0.3333333333333333, 0.3333333333333333]

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

我在打印点上发现了这一点。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]]

我注意到points数组中有六个条目,与我预期的四个相反,因为输入的Shape对象是矩形2D。双精度(0,0,1,1)。很明显,它比我想要的多解释了点(0,0)两次,我不明白为什么会这样。它是PathIterator的结果。isDone()方法?我用错了吗?如果PathIterator无法解决问题,该怎么办


共 (3) 个答案

  1. # 1 楼答案

    正如已经指出的,PathIterator返回不同类型的段。仅考虑SEG_LINETO中涉及的点时,应已获得令人满意的结果。然而,考虑到也可能有其他形状的SexGuthto和SeCube CuButo。使用展平路径迭代器可以很容易地避免这些问题:使用

    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);
        }
    
    }
    
  2. # 2 楼答案

    我不确定您是否错误地使用了它,但是您没有考虑到PathIterator的一个方面。PathIterator与其说代表一个几何图形,不如说代表一个在绘制时应该采用的路径。因此,它的点也代表了“笔”应该走的路径类型。例如,对于矩形,路径将生成以下线段:

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

    因为路径显然应该:

    • 无论笔在哪里,都要移动,而不是画画
    • 将此路径与笔下一步绘制的内容隔开

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

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

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

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

  3. # 3 楼答案

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