2

I have a UIBezierPath that I need to get point y when I set point x

thanks

FBente
  • 2,160
  • 23
  • 34
Arash Zeinoddini
  • 801
  • 13
  • 19
  • The question is more than unclear. You need to get "point y" of what exactly? What do you mean by "point x" and "point y"? Are you talking about the x and y coordinates of one point or two different points? Please describe your problem. – nullp01nter Oct 17 '12 at 05:43
  • 1
    yes, i mean how can i get y coordinate of my path in x coordinate, like http://imageshack.us/photo/my-images/21/iossimulatorscreenshoto.png/ – Arash Zeinoddini Oct 17 '12 at 09:39

2 Answers2

3

You will need to interpolate between the points. To access the points, it would be easiest to have them stored into an NSMutableArray. Create this array and add all CGPoints while you add them to your UIBezierPath in your drawing routine. If this is not possible, see here on how to extract points from a UIBezierPath. See code below on how to achieve what you want:

-(float)getYValueFromArray:(NSArray*)a atXValue:(float)x
{
    NSValue *v1, *v2;
    float x1, x2, y1, y2;

    // iterate through all points
    for(int i=0; i<([a count]-1); i++)
    {
        // get current and next point
        v1 = [a objectAtIndex:i];
        v2 = [a objectAtIndex:i+1];

        // return if value matches v1.x or v2.x
        if(x==[v1 CGPointValue].x) return [v1 CGPointValue].y;
        if(x==[v2 CGPointValue].x) return [v2 CGPointValue].y;

        // if x is between v1.x and v2.x calculate interpolated value
        if((x>[v1 CGPointValue].x) && (x<[v2 CGPointValue].x))
        {
            x1 = [v1 CGPointValue].x;
            x2 = [v2 CGPointValue].x;
            y1 = [v1 CGPointValue].y;
            y2 = [v2 CGPointValue].y;
            return (x-x1)/(x2-x1)*(y2-y1) + y1;
        }
    }

    // should never reach this point
    return -1;
}

-(void)test
{
    NSMutableArray *a = [[NSMutableArray alloc] init];
    [a addObject:[NSValue valueWithCGPoint:CGPointMake( 0, 10)]];
    [a addObject:[NSValue valueWithCGPoint:CGPointMake(10,  5)]];
    [a addObject:[NSValue valueWithCGPoint:CGPointMake(15, 20)]];
    [a addObject:[NSValue valueWithCGPoint:CGPointMake(20, 30)]];
    [a addObject:[NSValue valueWithCGPoint:CGPointMake(35, 50)]];
    [a addObject:[NSValue valueWithCGPoint:CGPointMake(50,  0)]];

    float y = [self getYValueFromArray:a atXValue:22.5];
    NSLog(@"Y value at X=22.5 is %.2f", y);
}
Community
  • 1
  • 1
nullp01nter
  • 522
  • 4
  • 18
  • Yes, but he didn't ask for curves. His initial question was very vague and probably impossible to answer. But from his first comment and the picture link you see a chart consisting of lines, that's why I suggested this solution. – nullp01nter Oct 17 '12 at 12:26
  • 1
    you're Great @nullp01nter, it really helped me, nice idea, unfortunately my reputation isn't enough to vote up your answer, so could you vote up my question to vote up your answer, sorry its a little funny :) – Arash Zeinoddini Oct 17 '12 at 14:48
  • Nice to hear I could help. BTW, I voted up your comment, now your reputation is high enough. If you care, you could now vote up, too :) – nullp01nter Oct 17 '12 at 15:39
  • @JonathanCichon To start with curves you could check [this post](http://stackoverflow.com/a/16756481/4244501). – FBente Aug 03 '16 at 09:06
1

@nullp01nter Thanks for your nice answer. Exactly what i needed! :) Here is my Swift version of it as Extension for Arrays with PointXYs:

protocol PointXY {
    var x : CGFloat { get set }
    var y : CGFloat { get set }
}

extension CGPoint: PointXY { }

extension Array where Element: PointXY {
    func getYValue(forX x: CGFloat) -> CGFloat? {
        for index in 0..<(self.count - 1) {
            let p1 = self[index]
            let p2 = self[index + 1]
            // return p.y if a p.x matches x
            if x == p1.x { return p1.y }
            if x == p2.x { return p2.y }
            // if x is between p1.x and p2.x calculate interpolated value
            if x > p1.x && x < p2.x {
                let x1 = p1.x
                let x2 = p2.x
                let y1 = p1.y
                let y2 = p2.y
                return (x - x1) / (x2 - x1) * (y2 - y1) + y1
            }
        }
        return nil
    }
}
FBente
  • 2,160
  • 23
  • 34