Source

CS193P Assignment 1 / Calculator / GraphingView.m

//
//  GraphingView.m
//  Calculator
//
//  Created by Jay Yu on 21/07/12.
//  Copyright (c) 2012 JayYu.com. All rights reserved.
//

#import "GraphingView.h"
#import "AxesDrawer.h"

@implementation GraphingView
@synthesize dataSource = _dataSource;
@synthesize scale = _scale;
@synthesize origin = _origin;

#define DEFAULT_SCALE 1.00

- (CGFloat)scale
{
    if (!_scale) {
        return DEFAULT_SCALE; // don't allow zero scale
    } else {
        return _scale;
    }
}

- (void)setScale:(CGFloat)scale
{
    if (scale != _scale) {
        _scale = scale;
        [self setNeedsDisplay]; // any time our scale changes, call for redraw
    }
}

- (CGPoint)origin
{
    if (!_origin.x && !_origin.y) {
        _origin = CGPointMake(self.bounds.origin.x + self.bounds.size.width / 2, self.bounds.origin.y + self.bounds.size.height / 2);
    }
    return _origin;
}

- (void)setOrigin:(CGPoint)origin
{
    if (origin.x != _origin.x && origin.y != _origin.y) {
        _origin = origin;
        [self setNeedsDisplay]; // any time our scale changes, call for redraw
    }
}

- (void)pinch:(UIPinchGestureRecognizer *)gesture
{
    if ((gesture.state == UIGestureRecognizerStateChanged) ||
        (gesture.state == UIGestureRecognizerStateEnded)) {
        self.scale *= gesture.scale; // adjust our scale
        gesture.scale = 1;           // reset gestures scale to 1 (so future changes are incremental, not cumulative)
    }
}

- (void)pan:(UIPanGestureRecognizer *)gesture
{
    if ((gesture.state == UIGestureRecognizerStateChanged) ||
        (gesture.state == UIGestureRecognizerStateEnded)) {
        CGPoint translation = [gesture translationInView:self];
        self.origin = CGPointMake(self.origin.x + translation.x, self.origin.y + translation.y);
        [gesture setTranslation:CGPointZero inView:self];
    }
}

- (void)tripleTap:(UITapGestureRecognizer *)gesture
{
    if (gesture.state == UIGestureRecognizerStateEnded) {
        CGPoint new_origin = [gesture locationInView:self];
        self.origin = new_origin;
    }
}

- (void)drawRect:(CGRect)rect
{
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGPoint midPoint = self.origin; // center of our bounds in our coordinate system

    CGFloat scale = self.scale;

    [AxesDrawer drawAxesInRect:rect originAtPoint:midPoint scale:scale];

    CGFloat x = 0.0;  // Always begin drawing from the left edge of the UIView
    CGFloat y;
    double x_t;  // X Axis UIView coordinate - converted from CGFloat to the graph coordination system
    double y_t;  // Raw Y Axis value returned from runProgram
    BOOL drawing = NO;

    while (x < self.bounds.size.width) {
        x_t = [self translateCoordinateToAxisValue:x originAtPoint:midPoint scale:scale];
        y_t = [self.dataSource yAxisValue:self atXAxis:x_t];
        y = [self translateAxisValueToCoordinate:y_t originAtPoint:midPoint scale:scale];
        if (! drawing) {
            CGContextBeginPath(context);
            CGContextMoveToPoint(context, x, y);
        } else {
            CGContextAddLineToPoint(context, x, y);
// Use this if clause to debug
//            if ((midPoint.x - x) > -10.00 && (midPoint.x - x) < 10.00) {
//                NSLog(@"Drawing: x: %f x_t: %f y: %f y_t: %f at scale %f", x, x_t, y, y_t, self.scale);
//            }
        }
        drawing = YES;
        x = x + (1.0 / self.contentScaleFactor);  // Support hi-res drawing on Retina devices
    }
    [[UIColor blueColor] setStroke];
    CGContextDrawPath(context, kCGPathStroke);
}

- (double)translateCoordinateToAxisValue:(CGFloat)x
                           originAtPoint:(CGPoint)midPoint
                                   scale:(CGFloat)scale
{
    CGFloat val = (x - midPoint.x) / scale;
    return (double) val;
}

- (CGFloat)translateAxisValueToCoordinate:(double)y
                           originAtPoint:(CGPoint)midPoint
                                   scale:(CGFloat)scale
{
    CGFloat val = (CGFloat) y * scale;
    return midPoint.y - val;
}

- (void)setup
{
    self.contentMode = UIViewContentModeRedraw; // if our bounds changes, redraw ourselves
}

- (void)awakeFromNib
{
    [self setup]; // get initialized when we come out of a storyboard
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

@end