将 xy 坐标(以像素为单位)转换为重心坐标 (x,y,z)
Convert xy coordinates (in pixels) to barycentric coordinates (x,y,z)
这可能有点奇怪,但我有一张这样的三角形图形:
并且在测量平台中,每当点击此图形中的一个点时, 像素 中的 x,y 坐标会这样记录(x,y 的原点来自图片的左上角)
注意:点击只能在绿色三角形内。
有没有办法将这些坐标转换为相对于二维单纯形(此三角形)的重心坐标 (x,y,z)?
如果是的话,考虑到我们有 像素 .
中的 x,y,合适的方程式是什么
它们是以像素为单位还是仍然被视为笛卡尔坐标会很重要吗?
谢谢!
像素只是特定的单位,这个三角形表示仍然是笛卡尔坐标,所以你只需应用相同的公式,即(如评论中指定)this
所以你知道三角形三个顶点的坐标
A: {ax, ay}
B: {bx, by}
C: {cx, cy}
而你想取任意点
P: {px, py}
并找到三个重心坐标 w_A
、w_B
、w_C
使得
px = w_A * ax + w_B * bx + w_C * cx
py = w_A * ay + w_B * by + w_C * cy
1 = w_A + w_B + w_C
将其转化为线性代数问题
| px | | ax bx cx | | w_A |
| py | = | ay by cy | | w_B |
| 1 | | 1 1 1 | | w_C |
待解决 {w_A,w_B,w_C}
使用下面我测试的示例代码得到以下结果
Triangle A: <5, 0>
Triangle B: <2.5, 5>
Triangle C: <0, 0>
Random Point: <3.169941, 0.417091>
Barycentric: (0.5922791,0.08341819,0.3243028)
Target Point: <3.169941, 0.417091>
Triangle.cs
using System.Numerics;
namespace ConsoleApp2
{
public class Triangle
{
public Triangle(Vector2 a, Vector2 b, Vector2 c)
{
A = a;
B = b;
C = c;
}
public Vector2 A { get; set; }
public Vector2 B { get; set; }
public Vector2 C { get; set; }
public Vector2 GetPoint(float w_A, float w_B, float w_C) => GetPoint((w_A, w_B, w_C));
public Vector2 GetPoint((float w_A, float w_B, float w_C) coord)
{
return coord.w_A * A + coord.w_B * B + coord.w_C * C;
}
public (float w_A, float w_B, float w_C) GetBarycentric(Vector2 P)
{
float D = A.X * (B.Y - C.X) + A.Y * (B.X - C.X) + B.X * C.Y - B.Y * C.X;
float w_A = ((B.Y - C.Y) * P.X + (C.X - B.X) * P.Y + (B.X * C.Y - B.Y * C.X)) / D;
float w_B = ((C.Y - A.Y) * P.X + (A.X - C.X) * P.Y + (C.X * A.Y - C.Y * A.X)) / D;
float w_C = ((A.Y - B.Y) * P.X + (B.X - A.X) * P.Y + (A.X * B.Y - A.Y * B.X)) / D;
return (w_A, w_B, w_C);
}
public bool Contains(Vector2 point)
{
var (w_A, w_B, w_C) = GetBarycentric(point);
return w_A>=0 && w_A<=1
&& w_B>=0 && w_B<=1
&& w_C>=0 && w_C<=1;
}
}
}
Program.cs
using System;
using System.Numerics;
namespace ConsoleApp2
{
public static class Program
{
static readonly Random rng = new Random();
static Vector2 RandomVector(float minValue = 0, float maxValue = 1)
{
return new Vector2(
minValue + (maxValue - minValue) * (float)rng.NextDouble(),
minValue + (maxValue - minValue) * (float)rng.NextDouble());
}
static void Main(string[] args)
{
Vector2 A = new Vector2(5f,0f);
Vector2 B = new Vector2(2.5f,5f);
Vector2 C = new Vector2(0f,0f);
var triangle = new Triangle(A, B, C);
Console.WriteLine($"Triangle A: {A}");
Console.WriteLine($"Triangle B: {B}");
Console.WriteLine($"Triangle C: {C}");
Vector2 P = RandomVector(0f, 5f);
Console.WriteLine($"Random Point: {P}");
var (w_A, w_B, w_C) = triangle.GetBarycentric(P);
Console.WriteLine($"Barycentric: ({w_A},{w_B},{w_C})");
Vector2 T = triangle.GetPoint(w_A, w_B, w_C);
Console.WriteLine($"Target Point: {T}");
}
}
}
这可能有点奇怪,但我有一张这样的三角形图形:
并且在测量平台中,每当点击此图形中的一个点时, 像素 中的 x,y 坐标会这样记录(x,y 的原点来自图片的左上角)
注意:点击只能在绿色三角形内。
有没有办法将这些坐标转换为相对于二维单纯形(此三角形)的重心坐标 (x,y,z)?
如果是的话,考虑到我们有 像素 .
中的 x,y,合适的方程式是什么它们是以像素为单位还是仍然被视为笛卡尔坐标会很重要吗?
谢谢!
像素只是特定的单位,这个三角形表示仍然是笛卡尔坐标,所以你只需应用相同的公式,即(如评论中指定)this
所以你知道三角形三个顶点的坐标
A: {ax, ay}
B: {bx, by}
C: {cx, cy}
而你想取任意点
P: {px, py}
并找到三个重心坐标 w_A
、w_B
、w_C
使得
px = w_A * ax + w_B * bx + w_C * cx
py = w_A * ay + w_B * by + w_C * cy
1 = w_A + w_B + w_C
将其转化为线性代数问题
| px | | ax bx cx | | w_A |
| py | = | ay by cy | | w_B |
| 1 | | 1 1 1 | | w_C |
待解决 {w_A,w_B,w_C}
使用下面我测试的示例代码得到以下结果
Triangle A: <5, 0>
Triangle B: <2.5, 5>
Triangle C: <0, 0>
Random Point: <3.169941, 0.417091>
Barycentric: (0.5922791,0.08341819,0.3243028)
Target Point: <3.169941, 0.417091>
Triangle.cs
using System.Numerics;
namespace ConsoleApp2
{
public class Triangle
{
public Triangle(Vector2 a, Vector2 b, Vector2 c)
{
A = a;
B = b;
C = c;
}
public Vector2 A { get; set; }
public Vector2 B { get; set; }
public Vector2 C { get; set; }
public Vector2 GetPoint(float w_A, float w_B, float w_C) => GetPoint((w_A, w_B, w_C));
public Vector2 GetPoint((float w_A, float w_B, float w_C) coord)
{
return coord.w_A * A + coord.w_B * B + coord.w_C * C;
}
public (float w_A, float w_B, float w_C) GetBarycentric(Vector2 P)
{
float D = A.X * (B.Y - C.X) + A.Y * (B.X - C.X) + B.X * C.Y - B.Y * C.X;
float w_A = ((B.Y - C.Y) * P.X + (C.X - B.X) * P.Y + (B.X * C.Y - B.Y * C.X)) / D;
float w_B = ((C.Y - A.Y) * P.X + (A.X - C.X) * P.Y + (C.X * A.Y - C.Y * A.X)) / D;
float w_C = ((A.Y - B.Y) * P.X + (B.X - A.X) * P.Y + (A.X * B.Y - A.Y * B.X)) / D;
return (w_A, w_B, w_C);
}
public bool Contains(Vector2 point)
{
var (w_A, w_B, w_C) = GetBarycentric(point);
return w_A>=0 && w_A<=1
&& w_B>=0 && w_B<=1
&& w_C>=0 && w_C<=1;
}
}
}
Program.cs
using System;
using System.Numerics;
namespace ConsoleApp2
{
public static class Program
{
static readonly Random rng = new Random();
static Vector2 RandomVector(float minValue = 0, float maxValue = 1)
{
return new Vector2(
minValue + (maxValue - minValue) * (float)rng.NextDouble(),
minValue + (maxValue - minValue) * (float)rng.NextDouble());
}
static void Main(string[] args)
{
Vector2 A = new Vector2(5f,0f);
Vector2 B = new Vector2(2.5f,5f);
Vector2 C = new Vector2(0f,0f);
var triangle = new Triangle(A, B, C);
Console.WriteLine($"Triangle A: {A}");
Console.WriteLine($"Triangle B: {B}");
Console.WriteLine($"Triangle C: {C}");
Vector2 P = RandomVector(0f, 5f);
Console.WriteLine($"Random Point: {P}");
var (w_A, w_B, w_C) = triangle.GetBarycentric(P);
Console.WriteLine($"Barycentric: ({w_A},{w_B},{w_C})");
Vector2 T = triangle.GetPoint(w_A, w_B, w_C);
Console.WriteLine($"Target Point: {T}");
}
}
}