This may be a strange one but I have a graphic of a triangle like this:
and in a survey platform, whenever one click on a point in this graphic an x,y coordinates in pixels are recorded like this (the origin for x,y is from the top-left of the image)
Note: the clicking is only allowed inside the green triangle.
Is there a way to convert these coordinates to barycentric coordinates (x,y,z) with respect to a simplex in 2D (this triangle)?
If so what is the appropriate equation given that we have the x,y in pixels.
Would it matter if they are in pixels or are they still considered Cartesian coordinates?
Thanks!
CodePudding user response:
So you know the coordinates of the three vertex of the triangle
A: {ax, ay}
B: {bx, by}
C: {cx, cy}
and you want to take an arbitrary point
P: {px, py}
and find the three barycentric coordinates w_A
, w_B
, w_C
such that
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
Turn this into a linear algebra problem
| px | | ax bx cx | | w_A |
| py | = | ay by cy | | w_B |
| 1 | | 1 1 1 | | w_C |
to be solved for {w_A,w_B,w_C}
Use the sample code below which I tested with the following results
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}");
}
}
}
CodePudding user response:
Pixels are just the specific unit, this triangle representation would still be in cartesian coordinates, so you just apply the same formula, i.e. (as specified in the comments )this