获取三角形内的所有点导致溢出
Get all points within a triangle is causing an overflow
好吧,我在 Unity 中缺少 GraphicsPath(通常用于填充多边形、绘制多边形和轮廓以及具有形状的实用程序),所以我正在自己实现它。好吧,我们也可以讨论哪个是最好的选择,但实际上,我更喜欢这个,因为我学到了很多东西。
思路如下,给定一个多边形,我们用 ClipperLib 做一个偏移多边形(向内和向外),然后用 LibTessDotNet 对它进行三角测量,输出:
绿色、蓝色和黄色像素是每个三角形的边。这种形状的 LibTessDotNet 输出类似 501 个三角形。
所以,感谢@SimpleVar I done this:
public static IEnumerable<T> PointsInTriangle<T>(T pt1, T pt2, T pt3)
where T : IPoint
{
/*
// https://www.geeksforgeeks.org/check-whether-triangle-valid-not-sides-given/
a + b > c
a + c > b
b + c > a
*/
float a = Vector2.Distance(new Vector2(pt1.x, pt1.y), new Vector2(pt2.x, pt2.y)),
b = Vector2.Distance(new Vector2(pt2.x, pt2.y), new Vector2(pt3.x, pt3.y)),
c = Vector2.Distance(new Vector2(pt3.x, pt3.y), new Vector2(pt1.x, pt1.y));
// (new[] { pt1, pt2, pt3 }).Distinct(new PointComparer()).Count() == 0
if (a + b <= c || a + c <= b || b + c <= a)
{
Debug.LogWarning($"The given points must form a triangle. {{{pt1}, {pt2}, {pt3}}}");
yield break;
}
T tmp;
if (pt2.x < pt1.x)
{
tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
if (pt3.x < pt2.x)
{
tmp = pt2;
pt2 = pt3;
pt3 = tmp;
if (pt2.x < pt1.x)
{
tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
}
var baseFunc = CreateFunc(pt1, pt3);
var line1Func = pt1.x == pt2.x ? (x => pt2.y) : CreateFunc(pt1, pt2);
for (var x = pt1.x; x < pt2.x; ++x)
{
int maxY;
int minY = GetRange(line1Func(x), baseFunc(x), out maxY);
for (int y = minY; y <= maxY; ++y)
yield return (T)Activator.CreateInstance(typeof(T), x, y);
}
var line2Func = pt2.x == pt3.x ? (x => pt2.y) : CreateFunc(pt2, pt3);
for (var x = pt2.x; x <= pt3.x; ++x)
{
int maxY;
int minY = GetRange(line2Func(x), baseFunc(x), out maxY);
for (int y = minY; y <= maxY; ++y)
yield return (T)Activator.CreateInstance(typeof(T), x, y);
}
}
private static int GetRange(float y1, float y2, out int maxY)
{
if (y1 < y2)
{
maxY = Mathf.FloorToInt(y2);
return Mathf.CeilToInt(y1);
}
maxY = Mathf.FloorToInt(y1);
return Mathf.CeilToInt(y2);
}
private static Func<int, float> CreateFunc<T>(T pt1, T pt2)
where T : IPoint
{
var y0 = pt1.y;
if (y0 == pt2.y)
return x => y0;
float m = (float)(pt2.y - y0) / (pt2.x - pt1.x);
return x => m * (x - pt1.x) + y0;
}
实际上它可以工作,但不太好。因为它会导致溢出(由于此代码使用了大量 RAM,我不得不使用 Process Explorer 终止 Unity 进程)。
我用断点调试了这个东西,但我想不通问题到底在哪里。
我认为问题出在 for (var x = pt1.x; x < pt2.x; ++x)
或 for (int y = minY; y <= maxY; ++y)
或下一个块中...但正如我所说,我无法像在 WinForms 中习惯的那样进行调试。当达到溢出时 Visual Studio 停止调试并且 Unity 崩溃,所以我有点卡住了。
我试着做一个 DotNetFiddle 做溢出,但我在这里什么也想不通...所以...我不知道我能做些什么来改进代码。
向我解释您发现的所有未优化的内容,以及我可以采取哪些方法来改进我的主要目标。
好的,我解决了问题是面积等于或小于 1 的三角形正在溢出。用苍鹭公式检查这个我解决了它:
public static float TriangleArea(Point p1, Point p2, Point p3)
{
float a, b, c;
if (!CheckIfValidTriangle(p1, p2, p3, out a, out b, out c))
return 0;
return TriangleArea(a, b, c);
}
public static float TriangleArea(float a, float b, float c)
{
// Thanks to: http://james-ramsden.com/area-of-a-triangle-in-3d-c-code/
float s = (a + b + c) / 2.0f;
return Mathf.Sqrt(s * (s - a) * (s - b) * (s - c));
}
然后:
if (TriangleArea(pt1, pt2, pt3) <= 1)
return;
也许(我没有测试)但它可能是由泛型引起的。
无论如何,我在 Gist Github 上发布了这个不错的 TriangleUtils。给定一个用 LibTessDotNet 镶嵌的三角形列表,我们可以对其进行栅格化:https://gist.github.com/z3nth10n/7d60f22c7e906f645d53c9622507c23b
我上传了以下视频,展示了我取得的成就:https://youtu.be/7yY3MIyRtPw
好吧,我在 Unity 中缺少 GraphicsPath(通常用于填充多边形、绘制多边形和轮廓以及具有形状的实用程序),所以我正在自己实现它。好吧,我们也可以讨论哪个是最好的选择,但实际上,我更喜欢这个,因为我学到了很多东西。
思路如下,给定一个多边形,我们用 ClipperLib 做一个偏移多边形(向内和向外),然后用 LibTessDotNet 对它进行三角测量,输出:
绿色、蓝色和黄色像素是每个三角形的边。这种形状的 LibTessDotNet 输出类似 501 个三角形。
所以,感谢@SimpleVar I done this:
public static IEnumerable<T> PointsInTriangle<T>(T pt1, T pt2, T pt3)
where T : IPoint
{
/*
// https://www.geeksforgeeks.org/check-whether-triangle-valid-not-sides-given/
a + b > c
a + c > b
b + c > a
*/
float a = Vector2.Distance(new Vector2(pt1.x, pt1.y), new Vector2(pt2.x, pt2.y)),
b = Vector2.Distance(new Vector2(pt2.x, pt2.y), new Vector2(pt3.x, pt3.y)),
c = Vector2.Distance(new Vector2(pt3.x, pt3.y), new Vector2(pt1.x, pt1.y));
// (new[] { pt1, pt2, pt3 }).Distinct(new PointComparer()).Count() == 0
if (a + b <= c || a + c <= b || b + c <= a)
{
Debug.LogWarning($"The given points must form a triangle. {{{pt1}, {pt2}, {pt3}}}");
yield break;
}
T tmp;
if (pt2.x < pt1.x)
{
tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
if (pt3.x < pt2.x)
{
tmp = pt2;
pt2 = pt3;
pt3 = tmp;
if (pt2.x < pt1.x)
{
tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
}
var baseFunc = CreateFunc(pt1, pt3);
var line1Func = pt1.x == pt2.x ? (x => pt2.y) : CreateFunc(pt1, pt2);
for (var x = pt1.x; x < pt2.x; ++x)
{
int maxY;
int minY = GetRange(line1Func(x), baseFunc(x), out maxY);
for (int y = minY; y <= maxY; ++y)
yield return (T)Activator.CreateInstance(typeof(T), x, y);
}
var line2Func = pt2.x == pt3.x ? (x => pt2.y) : CreateFunc(pt2, pt3);
for (var x = pt2.x; x <= pt3.x; ++x)
{
int maxY;
int minY = GetRange(line2Func(x), baseFunc(x), out maxY);
for (int y = minY; y <= maxY; ++y)
yield return (T)Activator.CreateInstance(typeof(T), x, y);
}
}
private static int GetRange(float y1, float y2, out int maxY)
{
if (y1 < y2)
{
maxY = Mathf.FloorToInt(y2);
return Mathf.CeilToInt(y1);
}
maxY = Mathf.FloorToInt(y1);
return Mathf.CeilToInt(y2);
}
private static Func<int, float> CreateFunc<T>(T pt1, T pt2)
where T : IPoint
{
var y0 = pt1.y;
if (y0 == pt2.y)
return x => y0;
float m = (float)(pt2.y - y0) / (pt2.x - pt1.x);
return x => m * (x - pt1.x) + y0;
}
实际上它可以工作,但不太好。因为它会导致溢出(由于此代码使用了大量 RAM,我不得不使用 Process Explorer 终止 Unity 进程)。
我用断点调试了这个东西,但我想不通问题到底在哪里。
我认为问题出在 for (var x = pt1.x; x < pt2.x; ++x)
或 for (int y = minY; y <= maxY; ++y)
或下一个块中...但正如我所说,我无法像在 WinForms 中习惯的那样进行调试。当达到溢出时 Visual Studio 停止调试并且 Unity 崩溃,所以我有点卡住了。
我试着做一个 DotNetFiddle 做溢出,但我在这里什么也想不通...所以...我不知道我能做些什么来改进代码。
向我解释您发现的所有未优化的内容,以及我可以采取哪些方法来改进我的主要目标。
好的,我解决了问题是面积等于或小于 1 的三角形正在溢出。用苍鹭公式检查这个我解决了它:
public static float TriangleArea(Point p1, Point p2, Point p3)
{
float a, b, c;
if (!CheckIfValidTriangle(p1, p2, p3, out a, out b, out c))
return 0;
return TriangleArea(a, b, c);
}
public static float TriangleArea(float a, float b, float c)
{
// Thanks to: http://james-ramsden.com/area-of-a-triangle-in-3d-c-code/
float s = (a + b + c) / 2.0f;
return Mathf.Sqrt(s * (s - a) * (s - b) * (s - c));
}
然后:
if (TriangleArea(pt1, pt2, pt3) <= 1)
return;
也许(我没有测试)但它可能是由泛型引起的。
无论如何,我在 Gist Github 上发布了这个不错的 TriangleUtils。给定一个用 LibTessDotNet 镶嵌的三角形列表,我们可以对其进行栅格化:https://gist.github.com/z3nth10n/7d60f22c7e906f645d53c9622507c23b
我上传了以下视频,展示了我取得的成就:https://youtu.be/7yY3MIyRtPw