I understand now.
The solution to this depends on how the points that define the curve are specified.
If all the points are defined with the same x steps, then you can simple use the GetPositionOnCurve where t = x. An example would be (first column x, second column r):
0.0 r1
0.2 r2
0.4 r3
0.6 r4
0.8 r5
1.0 r6
But I assume the user of your application can define the points in the way he wants. In this case the distribution of x values in not equal - for example:
0.0 r1
0.6 r2
0.8 r3
1.0 r4
If you would call GetPositionOnCurve with t = 0.5, you would get a value between second and third radius and not a value for x = 0.5 (between r1 and r2 and closer to r2).
If the x values are always increasing (if the curve does not go down and then up again), then it is possible to use bisection algorithm to find the radius value for given x.
The following code does that:
Code:
public static double GetRadius(double x, BezierCurve bezierCurve)
{
double accuracy = 0.00001; // How accurate the result should be (lower number means bigger accuracy but more steps - no worried for performance - this is executed very fast)
double tLower = 0;
double tUpper = 1;
int count = 0;
while (count < 10000) // just in case we cannot find the number accurate enough we limit number of iterations
{
double middle = (tLower + tUpper) / 2.0;
Point3D pMiddle = bezierCurve.GetPositionOnCurve(middle);
double middleX = pMiddle.X;
if (Math.Abs(middleX - x) <= accuracy) // If we have a result that is accurate enough ...
return pMiddle.Y; // ... we can return the Y value
if (middleX < x)
tLower = middle;
else
tUpper = middle;
count ++;
}
return double.NaN; // No result found (maybe the x is out of range or accuracy is too small number)
}
The GetRadius method can be tested with the following:
Code:
var controlPoints = new List<Point3D>();
controlPoints.Add(new Point3D(0.0, 50, 0));
controlPoints.Add(new Point3D(0.5, 100, 0));
controlPoints.Add(new Point3D(0.8, 70, 0));
controlPoints.Add(new Point3D(1.0, 50, 0));
var bezierCurve = BezierCurve.CreateFromCurvePositions(controlPoints);
double radius = GetRadius(0.2, bezierCurve); // Get radius for x = 0.2
radius = GetRadius(0.4, bezierCurve);
radius = GetRadius(0.99, bezierCurve);
Because CreateFromCurvePositions requires Point3D collection, I have converted the list of 2D points with x and radius into Point3D where X = x, Y = radius, Z = 0
You can play with different accuracy settings and check how accurate the results are and how many iterations are needed for that (set breakpoint to return statement and check the count value).
Note once again that this works only when the x values are always ascending (or always descending) and do change direction - in this case there would be multiple solutions but this algorithm would not find them.
I hope that this will work well for you.