Arash Zeinoddini
Arash Zeinoddini

Reputation: 819

Get UIBezierPath point.y with set point.x iphone

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

thanks

Upvotes: 2

Views: 1627

Answers (2)

FBente
FBente

Reputation: 2180

@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
    }
}

Upvotes: 1

nullp01nter
nullp01nter

Reputation: 521

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);
}

Upvotes: 3

Related Questions