gpt4 book ai didi

c# - GraphicsPath.IsClockWise() 扩展方法

转载 作者:太空狗 更新时间:2023-10-30 00:57:51 24 4
gpt4 key购买 nike

我需要为 GraphicsPath 对象创建一个扩展方法,以确定 GraphicsPath 是顺时针还是逆时针。

像这样:

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

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

return bClockWise;
}

注意:我只是假设我们需要在 GraphicsPath 中的点上使用 foreach ,但如果有更好的方法,请随时提供.

这是因为 GraphicsPathFillMode 决定相邻 GraphicsPath 的重叠部分是否被“填充”(Winding)或“洞”(备用)。但是,仅当相邻的 GraphicsPath 沿同一方向缠绕时才会出现这种情况。

Fillmode Winding vs Alternate

如果两条路径以相反的方向缠绕,即使将 FillMode 设置为 Winding 也会导致(不需要的)孔。

有趣的是,GraphicsPath 确实有一个 .Reverse() 方法允许改变路径的方向(这确实解决了问题),但不可能知道什么时候GraphicsPath 需要在不知道路径方向的情况下.Reversed。

你能帮忙看看这个扩展方法吗?

最佳答案

我之所以提出这个问题,主要是因为这个问题引起了我的兴趣,这是我不擅长的领域,我想引起讨论。

我拿了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

这还没有优化,它只是可能回答您的问题的东西。也许您自己已经想到了这一点。

希望得到建设性的批评。 :)

关于c# - GraphicsPath.IsClockWise() 扩展方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4208795/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com