- Home /
How to calculate curvature of a path?
Hello,
My question is a mathmetical question rather than unity, but while I am trying to calculate it in unity I think it is suitable to ask it in here.
I am trying to calculate curvature of path that is drawed with mouse.
At following picture you can see what is the aim of game. User have to draw a path that having optimal curvature.
And here is my code for calculating curvature.
float calculateCurvature()
{
//Choose points according to curvatureDelta
List<Vector2> choosenPoints = new List<Vector2>();
choosenPoints.Add(positions[0]);
//Positions list contains each position that is recorded in update function
for (int i = 1; i < positions.Count; i++)
{
//Curvature delta is minimum distance from previous point for acounting next point from positions list. With this condition if user doesn't move his mouse
//those points are not accounted and doesn't affect mean.
if (Vector2.Distance(positions[i], choosenPoints[choosenPoints.Count-1]) >= curvatureDelta) choosenPoints.Add(positions[i]);
}
//Create lines
List<Vector2> lines = new List<Vector2>();
for(int i = 1; i < choosenPoints.Count; i++)
{
Vector2 line = choosenPoints[i] - choosenPoints[i - 1];
lines.Add(line);
Debug.DrawLine(choosenPoints[i], choosenPoints[i - 1], Color.red, 1000000);
}
//Calculate angles
List<float> angles = new List<float>();
for (int i = 1; i < lines.Count; i++)
{
float angle = 180 - Vector2.Angle(-lines[i - 1], lines[i]);
angles.Add(angle);
//Debug.Log(angle);
}
return getMeanofList(angles);
}
However my code doesn't give stable result. So I thought I should apply a solid mathematical formula. But while path is drawed by user is not a smooth path I am not sure curvature formula will work in my case.
So I am looking a way to calculate curvature with a proper way.
I actually think a math Forum would be better, since your problem is very mathy and not really unity at all.
Answer by halfvoxel · Jun 21, 2017 at 12:08 PM
Hi
You can use the fact that curvature is τ = 1/r where r is the radius for the circle tangent to the curve. See https://en.wikipedia.org/wiki/Curvature#Curvature_of_plane_curves
var cc = CircleCenterFrom3Points(curve[t0].position), curve[t1].position, curve[t2].position);
var radius = (cc - To2D(curve[t1].position)).magnitude;
radius = Mathf.Max(radius, 0.0001f);
var curvature = 1 / radius;
where
/**
* Finds the center of the circle passing through the points p1, p2 and p3.
* (NaN, NaN) will be returned if the points are colinear.
*/
static Vector2 CircleCenterFrom3Points (Vector2 p1, Vector2 p2, Vector2 p3) {
float temp = p2.sqrMagnitude;
float bc = (p1.sqrMagnitude - temp)/2.0f;
float cd = (temp - p3.sqrMagnitude)/2.0f;
float det = (p1.x-p2.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p2.y);
if (Mathf.Abs(det) < 1.0e-6) {
return new Vector2(float.NaN, float.NaN);
}
det = 1/det;
return new Vector2((bc*(p2.y-p3.y)-cd*(p1.y-p2.y))*det, ((p1.x-p2.x)*cd-(p2.x-p3.x)*bc)*det);
}
and t0, t1, t2 are indices for 3 points on the curve. You can use i-1, i, i+1, but that will give you very noisy output. Use something like i-5, i, i+5 if you want smoother output.
Just wanted to say that this works super well. Don't know why this never got selected as the answer.