我需要为GraphicsPath对象创建一个扩展方法,确定GraphicsPath是顺时针还是逆时针缠绕。
像这样的:

    public static bool IsClockwise(GraphicsPath gp)
    {
        bool bClockWise = false;
        PointF[] pts = gp.PathPoints;

        foreach (PointF pt in pts)
        {
            //??
        }

        return bClockWise;
    }

注:我只是假设我们需要一个foreach关于GraphicsPath的点在这里,但如果有更好的方法,请随时提供。
原因是FillModeGraphicsPath决定了相邻图形空间的重叠部分是“填充”(Winding)还是“孔”(Alternate)。但是,只有在相邻的图形沿同一方向缠绕时,这才是正确的。
如果两条路径在相反的方向缠绕,即使将FillMode设置为Winding也会导致(不需要的)孔。
有趣的是,graphicspath确实有一个.Reverse()方法,允许改变路径的方向(这确实解决了问题),但是在不知道路径方向的情况下,不可能知道何时需要改变graphicspath。
你能帮我解决这个扩展方法吗?

最佳答案

我之所以这么说,主要是因为这个问题引起了我的兴趣,这是我没有专业知识的问题,我想引起大家的讨论。
我拿了Point in Polygon pseudo-code试着让它适合你的情况。你似乎只对确定某物是顺时针还是逆时针旋转感兴趣。这是一个简单的测试和一个非常简单的(边缘粗糙的)c实现。

[Test]
public void Test_DetermineWindingDirection()
{

    GraphicsPath path = new GraphicsPath();

    // Set up points collection
    PointF[] pts = new[] {new PointF(10, 60),
                    new PointF(50, 110),
                    new PointF(90, 60)};
    path.AddLines(pts);

    foreach(var point in path.PathPoints)
    {
        Console.WriteLine("X: {0}, Y: {1}",point.X, point.Y);
    }

    WindingDirection windingVal = DetermineWindingDirection(path.PathPoints);
    Console.WriteLine("Winding value: {0}", windingVal);
    Assert.AreEqual(WindingDirection.Clockwise, windingVal);

    path.Reverse();
    foreach(var point in path.PathPoints)
    {
        Console.WriteLine("X: {0}, Y: {1}",point.X, point.Y);
    }

    windingVal = DetermineWindingDirection(path.PathPoints);
    Console.WriteLine("Winding value: {0}", windingVal);
    Assert.AreEqual(WindingDirection.CounterClockWise, windingVal);
}

public enum WindingDirection
{
    Clockwise,
    CounterClockWise
}

public static WindingDirection DetermineWindingDirection(PointF[] polygon)
{
    // find a point in the middle
    float middleX = polygon.Average(p => p.X);
    float middleY = polygon.Average(p => p.Y);
    var pointInPolygon = new PointF(middleX, middleY);
    Console.WriteLine("MiddlePoint = {0}", pointInPolygon);

    double w = 0;
    var points = polygon.Select(point =>
                                    {
                                        var newPoint = new PointF(point.X - pointInPolygon.X, point.Y - pointInPolygon.Y);
                                        Console.WriteLine("New Point: {0}", newPoint);
                                        return newPoint;
                                    }).ToList();

    for (int i = 0; i < points.Count; i++)
    {
        var secondPoint = i + 1 == points.Count ? 0 : i + 1;
        double X = points[i].X;
        double Xp1 = points[secondPoint].X;
        double Y = points[i].Y;
        double Yp1 = points[secondPoint].Y;

        if (Y * Yp1 < 0)
        {
            double r = X + ((Y * (Xp1 - X)) / (Y - Yp1));
            if (r > 0)
                if (Y < 0)
                    w = w + 1;
                else
                    w = w - 1;
        }
        else if ((Y == 0) && (X > 0))
        {
            if (Yp1 > 0)
                w = w + .5;
            else
                w = w - .5;
        }
        else if ((Yp1 == 0) && (Xp1 > 0))
        {
            if (Y < 0)
                w = w + .5;
            else
                w = w - .5;
        }
    }
    return w > 0 ? WindingDirection.ClockWise : WindingDirection.CounterClockwise;
}

不同的是,我计算了所有点的x和y的平均值,并将其作为“多边形中的点”值。所以,只要传入一个点数组,它就会在其中找到一些东西。
我还假设,当v i+1到达点数组的边界时,它应该环绕,这样
if (i + 1 == points.Count)
    // use points[0] instead

这还没有优化,它只是一些潜在的答案你的问题。也许你已经自己想出来了。
希望能得到建设性的批评。:)

10-07 14:14