angle reflection

So I need a bit of help figuring out some angle reflection. I’ve figured out a large chunk of the problem proper hit detection for a polygon which can be drawn clockwise or counter clockwise. I know I’m super close, but I’m totally stuck.

I can get the perpendicular of the line segment of the collision. I know it’s just a matter of taking that angle finding the difference between it and the balls velocity vector and then doubling it, but it’s not working. Please take a look maybe someone can point out where I’m f-ing up.

Thanks!

testApp.mm

  
#include "testApp.h"  
  
//--------------------------------------------------------------  
void testApp::setup(){	  
	ofxiPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT);  
	  
	//ipad doesn't need no scale ;)   
	appIphoneScale = 1.0;  
    ofSetFrameRate(60);  
  
	ofBackground(255,255,255);	  
	ofSetFrameRate(60);  
      
    ofPoint tempP;  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
      
    clockwise = polyCurve(tri);  
      
    center = (tri[0] + tri[1] + tri[2])/3;  
    radius = 0;  
    for (int i=0; i<3 ; i++) {  
        float dist = ofDist(center.x, center.y, tri[i].x, tri[i].y);  
        if (dist > radius) {  
            radius = dist;  
        }  
    }  
      
    active = false;  
      
}  
  
//--------------------------------------------------------------  
void testApp::update(){  
    if (ballz.size() > 0) {  
        for (int i=0; i<ballz.size(); i++) {  
            ballz[i].update();  
              
              
            if (ballz[i].pos.x - ballz[i].radius <= 0) {  
                ballz[i].pos.x = 0 + ballz[i].radius;  
                ballz[i].vel.x *= -1;  
            }  
            if (ballz[i].pos.x + ballz[i].radius >= ofGetWidth()) {  
                ballz[i].pos.x = ofGetWidth() - ballz[i].radius;  
                ballz[i].vel.x *= -1;  
            }  
            if (ballz[i].pos.y - ballz[i].radius <= 0) {  
                ballz[i].pos.y = 0 + ballz[i].radius;  
                ballz[i].vel.y *= -1;  
            }  
            if (ballz[i].pos.y + ballz[i].radius >= ofGetHeight()) {  
                ballz[i].pos.y = ofGetHeight() - ballz[i].radius;  
                ballz[i].vel.y *= -1;  
            }  
              
            // The predicted position  
            ofPoint p1 = ballz[i].pos + (ballz[i].vel*ballz[i].edge);  
              
            //first check if the ball is withing a bounding box  
            //then start checking for more precise collision  
            if (insideBounds(ballz[i].pos, center, radius)) {  
                intersection = closestPointPoly(tri, ballz[i].pos);  
                  
                float dist = ofDist(ballz[i].pos.x, ballz[i].pos.y, intersection.x, intersection.y);  
                if (dist <= ballz[i].radius) {  
                    ballz[i].move = false;  
                }  
            }  
        }  
    }  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
  
	ofScale(appIphoneScale, appIphoneScale, 1.0);  
      
    ofSetColor(210, 210, 210);  
    ofCircle(center, radius); //bounding sphere  
  
    ofSetColor(255, 30, 30);  
    ofBeginShape();  
    for (int i=0; i<3; i++) {  
        ofVertex(tri[i].x, tri[i].y);  
        ofPushStyle();  
        ofSetColor(0);  
        ofDrawBitmapString(ofToString(i), tri[i]);  
        ofPopStyle();  
    }  
    ofEndShape(true);  
      
    if (ballz.size() > 0) {  
        for (int i=0; i<ballz.size(); i++) {  
            ballz[i].draw();  
              
            if (!ballz[i].move) {  
                ofPoint prev;  
                ofPushStyle();  
                ofSetLineWidth(1);  
                ofSetColor(0, 0, 255);  
                prev = ballz[i].pos - ballz[i].vel*50;  
                ofLine(ballz[i].pos.x, ballz[i].pos.y, prev.x, prev.y);  
                  
                ofPoint temp;  
                temp = resolveCollision(A, B, ballz[i].pos, ballz[i].vel);  
                  
                ofLine(intersection.x, intersection.y, temp.x, temp.y);  
                ofCircle(A, 5);  
                ofCircle(B, 5);  
                ofPopStyle();  
            }  
        }  
    }  
      
    ofSetColor(0);  
    ofCircle(intersection, 5);  
      
    ofDrawBitmapString("clockwise = " + ofToString(clockwise), 50,50);  
}  
  
//--------------------------------------------------------------  
void testApp::touchDown(ofTouchEventArgs &touch){  
    Ball newBall;  
    newBall.setup();  
    newBall.touchDown(touch);  
    ballz.clear();  
    ballz.push_back(newBall);  
}  
  
//--------------------------------------------------------------  
void testApp::touchMoved(ofTouchEventArgs &touch){  
    if (ballz.size() > 0) {  
        for (int i=0; i<ballz.size(); i++) {  
            if (!ballz[i].active) {  
                ballz[i].touchMoved(touch);  
            }  
        }  
    }  
}  
  
//--------------------------------------------------------------  
void testApp::touchUp(ofTouchEventArgs &touch){  
    if (ballz.size() > 0) {  
        for (int i=0; i<ballz.size(); i++) {  
            if (!ballz[i].active) {  
                ballz[i].touchUp(touch);  
            }  
        }  
    }  
}  
  
//--------------------------------------------------------------  
void testApp::touchDoubleTap(ofTouchEventArgs &touch){  
    tri.clear();  
      
    ofPoint tempP;  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
      
    clockwise = polyCurve(tri);  
      
    center = (tri[0] + tri[1] + tri[2])/3;  
    radius = 0;  
    for (int i=0; i<3 ; i++) {  
        float dist = ofDist(center.x, center.y, tri[i].x, tri[i].y);  
        if (dist > radius) {  
            radius = dist;  
        }  
    }  
}  
  
//--------------------------------------------------------------  
ofPoint testApp::closestPointPoly(vector<ofPoint> &poly, ofPoint bPos) {  
    vector<ofPoint> closestPoints;  
      
    if (clockwise) {  
        for (int i=0; i<poly.size(); i++) {  
            if (i==0) {  
                closestPoints.push_back(closestPointLine(poly[poly.size()-1], poly[i], bPos));  
            } else {  
                closestPoints.push_back(closestPointLine(poly[i-1], poly[i], bPos));  
            }  
        }  
    } else {  
        for (int i=0; i<poly.size(); i++) {  
            if (i==0) {  
                closestPoints.push_back(closestPointLine(poly[i], poly[poly.size()-1], bPos));  
            } else {  
                closestPoints.push_back(closestPointLine(poly[i], poly[i-1], bPos));  
            }  
        }  
    }      
      
    float dist = 10000;  
    ofPoint closest;  
    for (int i=0; i<closestPoints.size(); i++) {  
        float d = ofDist(closestPoints[i].x, closestPoints[i].y, bPos.x, bPos.y);  
        if (d < dist) {  
            closest = closestPoints[i];  
            dist = d;  
              
            if (clockwise) {  
                if (i == 0) {  
                    B = poly[poly.size()-1];  
                    A = poly[0];  
                } else {  
                    B = poly[i-1];  
                    A = poly[i];  
                }  
            } else {  
                if (i == 0) {  
                    A = poly[poly.size()-1];  
                    B = poly[0];  
                } else {  
                    A = poly[i-1];  
                    B = poly[i];  
                }  
            }  
              
        }  
    }  
    return closest;  
}  
  
//--------------------------------------------------------------  
ofPoint testApp::closestPointLine(ofPoint a, ofPoint b, ofPoint bPos) {  
    //trying to determine t ( the length of the vctor from a to bPos  
    ofPoint AP = bPos - a;  
    ofPoint AB = b - a;  
    float ab2 = AB.x*AB.x + AB.y*AB.y;  
    float ap_ab = AP.x*AB.x + AP.y*AB.y;  
    float t = ap_ab / ab2;  
      
    if (t < 0.0f) {  
        t = 0.0f;  
    } else if (t > 1.0f) {  
        t = 1.0f;  
    }  
    ofPoint closest = a + AB * t;  
    return closest;  
}  
  
  
//--------------------------------------------------------------  
ofPoint testApp::resolveCollision(ofPoint a, ofPoint b, ofPoint bPos, ofPoint bVel) {  
    float lineAngle = atan2(b.y - a.y, b.x - a.x);  
    float perpLine = lineAngle - PI/2;  
      
    float ballAngle = atan2(bVel.y, bVel.x);  
    float diff =  (ballAngle - perpLine) * 2;  
      
    if (diff  < -PI) {  
        diff += TWO_PI;  
    }  
    if (diff > PI) {  
        diff -= TWO_PI;  
    }  
      
    ofPoint line;  
//    line.x = intersection.x + cos(perpLine) *100;  
//    line.y = intersection.y + sin(perpLine) *100;  
  
    line.x = intersection.x + cos(diff) *100;  
    line.y = intersection.y + sin(diff) *100;  
      
    return line;  
}  
  
//--------------------------------------------------------------  
bool testApp::insideBounds(ofPoint bPos, ofPoint ctr, float rad) {  
    float dist = ofDist(ctr.x, ctr.y, bPos.x, bPos.y);  
    if (dist <= rad) {  
        return true;  
    } else {  
        return false;  
    }  
}  
  
//--------------------------------------------------------------  
bool testApp::polyCurve(vector<ofPoint> &poly) {  
    float sum = 0;  
    for (int i=0; i<poly.size(); i++) {  
        if (i==0) {  
            sum += (poly[i].x - poly[poly.size()-1].x) * (poly[i].y + poly[poly.size()-1].y);  
        } else {  
            sum += (poly[i].x - poly[i-1].x) * (poly[i].y + poly[i-1].y);  
        }  
    }  
      
    if (sum > 0) {  
        return true;  
    }  
    if (sum < 0) {  
        return false;  
    }  
}  
  
  

testApp.h

  
#pragma once  
  
#include "ofMain.h"  
#include "ofxiPhone.h"  
#include "ofxiPhoneExtras.h"  
#include "Ball.h"  
  
  
class testApp : public ofxiPhoneApp {  
	  
public:  
	void setup();  
	void update();  
	void draw();  
	  
	void touchDown(ofTouchEventArgs &touch);  
	void touchMoved(ofTouchEventArgs &touch);  
	void touchUp(ofTouchEventArgs &touch);  
	void touchDoubleTap(ofTouchEventArgs &touch);  
  
    ofPoint closestPointPoly(vector<ofPoint> &poly, ofPoint bPos);  
    ofPoint closestPointLine(ofPoint a, ofPoint b, ofPoint bPos);  
    ofPoint resolveCollision(ofPoint a, ofPoint b, ofPoint bPos, ofPoint bVel);  
    bool insideBounds(ofPoint bPos, ofPoint center, float radius);  
    bool polyCurve(vector<ofPoint> &poly);  
  
      
      
	float appIphoneScale;  
      
      
    vector<ofPoint> tri;  
    ofPoint center;  
    float radius;  
      
    ofPoint pos;  
    ofPoint vel;  
    bool active;  
    bool clockwise;  
      
    ofPoint intersection;  
    ofPoint normal;  
    ofPoint A, B;  
      
    vector<Ball> ballz;  
};  
  

Ball.mm

  
//  
//  Ball.cpp  
//  iPadExample  
//  
//  Created by Lee Williams on 4/11/12.  
//  Copyright (c) 2012 none. All rights reserved.  
//  
  
#include "Ball.h"  
  
void Ball::setup() {  
    active = false;  
    move = true;  
    pos.set(-100, -100);  
    radius = 10;  
    range = 3;  
    edge = radius/range;  
}  
  
  
void Ball::update() {  
    if (active) {  
        if (move) {  
            pos += vel;  
        }  
    }  
}  
  
  
void Ball::draw() {  
    if (active) {  
        ofPushStyle();  
        ofSetColor(0);  
        ofCircle(pos, radius);  
        ofSetColor(200, 200, 0);  
        ofLine(pos, pos + (vel*edge));  
        ofPopStyle();  
    }  
    else {  
        ofPushStyle();  
        ofNoFill();  
        ofSetLineWidth(2);  
        ofSetColor(0);  
        ofCircle(pos, radius);  
        ofLine(pos, tempDir);  
        ofPopStyle();  
    }  
}  
  
  
void Ball::touchDown(ofTouchEventArgs &touch) {  
    pos.set(touch.x, touch.y);  
    tempDir = pos;  
}  
  
  
void Ball::touchMoved(ofTouchEventArgs &touch) {  
    tempDir.set(touch.x, touch.y);  
}  
  
  
void Ball::touchUp(ofTouchEventArgs &touch) {  
    float angle = atan2(touch.y - pos.y, touch.x - pos.x);  
      
    vel.x = cos(angle) * range;  
    vel.y = sin(angle) * range;  
      
    active =  true;  
}  
  

Ball.h

  
//  
//  Ball.h  
//  iPadExample  
//  
//  Created by Lee Williams on 4/11/12.  
//  Copyright (c) 2012 none. All rights reserved.  
//  
  
#pragma once  
#include "ofMain.h"  
#include "ofxiPhone.h"  
#include "ofxiPhoneExtras.h"  
  
class Ball {  
      
public:  
    void setup();  
    void update();  
    void draw();  
      
    void touchDown(ofTouchEventArgs &touch);  
	void touchMoved(ofTouchEventArgs &touch);  
	void touchUp(ofTouchEventArgs &touch);  
	void touchDoubleTap(ofTouchEventArgs &touch);  
      
    ofPoint pos;  
    ofPoint vel;  
    bool active;  
    bool move;  
    float range;  
    float edge;  
    int radius;  
      
    ofPoint tempDir;  
};  
  

I figured it out my problem. I was a bit sleep deprived and burned out yesterday, but I saw my error this morning (sleep is magical). I struggled with this, so hopefully now whoever find this useful won’t have too. I commented some things, it’s pretty messy and could be fixed up a good bit.

testApp.h

  
  
#pragma once  
  
#include "ofMain.h"  
#include "ofxiPhone.h"  
#include "ofxiPhoneExtras.h"  
#include "Ball.h"  
  
  
class testApp : public ofxiPhoneApp {  
	  
public:  
	void setup();  
	void update();  
	void draw();  
	  
	void touchDown(ofTouchEventArgs &touch);  
	void touchMoved(ofTouchEventArgs &touch);  
	void touchUp(ofTouchEventArgs &touch);  
	void touchDoubleTap(ofTouchEventArgs &touch);  
  
    ofPoint closestPointPoly(vector<ofPoint> &poly, ofPoint bPos);  
    ofPoint closestPointLine(ofPoint a, ofPoint b, ofPoint bPos);  
    ofPoint resolveCollision(ofPoint a, ofPoint b, ofPoint bPos, ofPoint bVel, float speed);  
    bool insideBounds(ofPoint bPos, ofPoint center, float radius);  
    bool polyCurve(vector<ofPoint> &poly);  
  
      
      
	float appIphoneScale;  
      
      
    vector<ofPoint> tri;  
    ofPoint center;  
    float radius;  
      
    ofPoint pos;  
    ofPoint vel;  
    bool active;  
    bool clockwise;  
      
    ofPoint intersection;  
    ofPoint normal;  
    ofPoint A, B;  
      
    vector<Ball> ballz;  
};  
  

testApp.mm

  
  
#include "testApp.h"  
  
//--------------------------------------------------------------  
void testApp::setup(){	  
	ofxiPhoneSetOrientation(OFXIPHONE_ORIENTATION_LANDSCAPE_RIGHT);  
	  
	//ipad doesn't need no scale ;)   
	appIphoneScale = 1.0;  
    ofSetFrameRate(60);  
  
	ofBackground(255,255,255);	  
	ofSetFrameRate(60);  
      
    ofPoint tempP;  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
      
    clockwise = polyCurve(tri);  
      
    center.set(0, 0);  
    for (int i=0; i<tri.size() ; i++) {  
        center += tri[i];  
    }  
    center /= tri.size();  
      
    radius = 0;  
    for (int i=0; i<tri.size() ; i++) {  
        float dist = ofDist(center.x, center.y, tri[i].x, tri[i].y);  
        if (dist > radius) {  
            radius = dist;  
        }  
    }  
      
    active = false;  
      
}  
  
//--------------------------------------------------------------  
void testApp::update(){  
    if (ballz.size() > 0) {  
        for (int i=0; i<ballz.size(); i++) {  
            ballz[i].update();  
              
            //Simple colliding of wall checks  
            if (ballz[i].pos.x - ballz[i].radius <= 0) {  
                ballz[i].pos.x = 0 + ballz[i].radius;  
                ballz[i].vel.x *= -1;  
            }  
            if (ballz[i].pos.x + ballz[i].radius >= ofGetWidth()) {  
                ballz[i].pos.x = ofGetWidth() - ballz[i].radius;  
                ballz[i].vel.x *= -1;  
            }  
            if (ballz[i].pos.y - ballz[i].radius <= 0) {  
                ballz[i].pos.y = 0 + ballz[i].radius;  
                ballz[i].vel.y *= -1;  
            }  
            if (ballz[i].pos.y + ballz[i].radius >= ofGetHeight()) {  
                ballz[i].pos.y = ofGetHeight() - ballz[i].radius;  
                ballz[i].vel.y *= -1;  
            }  
  
            //first check if the ball is withing a bounding box  
            //then start checking for more precise collision  
            if (insideBounds(ballz[i].pos, center, radius)) {  
                intersection = closestPointPoly(tri, ballz[i].pos);  
                  
                float dist = ofDist(ballz[i].pos.x, ballz[i].pos.y, intersection.x, intersection.y);  
                if (dist <= ballz[i].radius + 1) {  
                    ballz[i].vel = resolveCollision(A, B, ballz[i].pos, ballz[i].vel, ballz[i].speed);  
                }  
            }  
        }  
    }  
}  
  
//--------------------------------------------------------------  
void testApp::draw(){  
  
	ofScale(appIphoneScale, appIphoneScale, 1.0);  
      
    ofSetColor(210, 210, 210);  
    ofCircle(center, radius); //bounding sphere  
  
    ofSetColor(255, 30, 30);  
    ofBeginShape();  
    for (int i=0; i<3; i++) {  
        ofVertex(tri[i].x, tri[i].y);  
        ofPushStyle();  
        ofSetColor(0);  
        ofDrawBitmapString(ofToString(i), tri[i]);  
        ofPopStyle();  
    }  
    ofEndShape(true);  
      
    if (ballz.size() > 0) {  
        for (int i=0; i<ballz.size(); i++) {  
            ballz[i].draw();  
        }  
    }  
}  
  
//--------------------------------------------------------------  
void testApp::touchDown(ofTouchEventArgs &touch){  
    Ball newBall;  
    newBall.setup();  
    newBall.touchDown(touch);  
    ballz.push_back(newBall);  
}  
  
//--------------------------------------------------------------  
void testApp::touchMoved(ofTouchEventArgs &touch){  
    if (ballz.size() > 0) {  
        for (int i=0; i<ballz.size(); i++) {  
            if (!ballz[i].active) {  
                ballz[i].touchMoved(touch);  
            }  
        }  
    }  
}  
  
//--------------------------------------------------------------  
void testApp::touchUp(ofTouchEventArgs &touch){  
    if (ballz.size() > 0) {  
        for (int i=0; i<ballz.size(); i++) {  
            if (!ballz[i].active) {  
                ballz[i].touchUp(touch);  
            }  
        }  
    }  
}  
  
//--------------------------------------------------------------  
void testApp::touchDoubleTap(ofTouchEventArgs &touch){  
    tri.clear();  
      
    ofPoint tempP;  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
    tempP.set((int)ofRandom(400,ofGetWidth()-400), (int)ofRandom(200,ofGetHeight()-200));  
    tri.push_back(tempP);  
      
    clockwise = polyCurve(tri);  
      
    center.set(0, 0);  
    for (int i=0; i<tri.size() ; i++) {  
        center += tri[i];  
    }  
    center /= tri.size();  
      
    radius = 0;  
    for (int i=0; i<tri.size() ; i++) {  
        float dist = ofDist(center.x, center.y, tri[i].x, tri[i].y);  
        if (dist > radius) {  
            radius = dist;  
        }  
    }  
}  
  
//--------------------------------------------------------------  
ofPoint testApp::closestPointPoly(vector<ofPoint> &poly, ofPoint bPos) {  
    /*   
     need to find which side of the poly the ball is going to collide   
     with. To Optomize I'd want to figure this out once when the ball   
     immediately enters the bounding sphere. Maybe by projecting out   
     the balls vector * the bounding sphere's radius. See if it will   
     hit anything because it may just pass through the sphere without   
     collision.  
    */  
      
    vector<ofPoint> closestPoints;  
    /*  
    this is why it matters which direction the poly is drawn. The order   
     the points of the line segment are inspected kind of determines   
     which side of the line segment we're looking at.  
     */  
    if (clockwise) {  
        for (int i=0; i<poly.size(); i++) {  
            if (i==0) {  
                closestPoints.push_back(closestPointLine(poly[poly.size()-1], poly[i], bPos));  
            } else {  
                closestPoints.push_back(closestPointLine(poly[i-1], poly[i], bPos));  
            }  
        }  
    } else {  
        for (int i=0; i<poly.size(); i++) {  
            if (i==0) {  
                closestPoints.push_back(closestPointLine(poly[i], poly[poly.size()-1], bPos));  
            } else {  
                closestPoints.push_back(closestPointLine(poly[i], poly[i-1], bPos));  
            }  
        }  
    }      
    /*  
    this is pretty wonky but it works. Above we found the closest point   
     to our incoming ball on all line segments of the poly. Here we  
     determine which line segment is the one in which the ball will   
     actually hit. Too optomize I'd probably first want to find which line  
     segment first, then worry about the closest point.   
     */  
      
    float dist = 10000;  
    ofPoint closest;  
    for (int i=0; i<closestPoints.size(); i++) {  
        float d = ofDist(closestPoints[i].x, closestPoints[i].y, bPos.x, bPos.y);  
        if (d < dist) {  
            closest = closestPoints[i];  
            dist = d;  
            if (clockwise) {  
                if (i == 0) {  
                    B = poly[poly.size()-1];  
                    A = poly[0];  
                } else {  
                    B = poly[i-1];  
                    A = poly[i];  
                }  
            } else {  
                if (i == 0) {  
                    A = poly[poly.size()-1];  
                    B = poly[0];  
                } else {  
                    A = poly[i-1];  
                    B = poly[i];  
                }  
            }  
              
        }  
    }  
    return closest;  
}  
  
//--------------------------------------------------------------  
ofPoint testApp::closestPointLine(ofPoint a, ofPoint b, ofPoint bPos) {  
    //trying to determine t ( the length of the vector from a to bPos)  
    ofPoint AP = bPos - a;  
    ofPoint AB = b - a;  
    float ab2 = AB.x*AB.x + AB.y*AB.y;  
    float ap_ab = AP.x*AB.x + AP.y*AB.y;  
    float t = ap_ab / ab2;  
      
    if (t < 0.0f) {  
        t = 0.0f;  
    } else if (t > 1.0f) {  
        t = 1.0f;  
    }  
    ofPoint closest = a + AB * t;  
    return closest;  
}  
  
  
//--------------------------------------------------------------  
ofPoint testApp::resolveCollision(ofPoint a, ofPoint b, ofPoint bPos, ofPoint bVel, float speed) {  
    float lineAngle = atan2(b.y - a.y, b.x - a.x);  
    float perpLine = (lineAngle - PI/2);  
      
    float ballAngle = atan2((bPos.y - bVel.y) - bPos.y, (bPos.x -bVel.x) - bPos.x);  
    float diff =  ((perpLine - ballAngle) * 2) + ballAngle; //I was forgetting to apply the difference back to the balls original angle...  
      
    ofPoint newVel;  
    newVel.x = cos(diff) * speed;  
    newVel.y = sin(diff) * speed;  
      
    return newVel;  
}  
  
//--------------------------------------------------------------  
bool testApp::insideBounds(ofPoint bPos, ofPoint ctr, float rad) {  
    float dist = ofDist(ctr.x, ctr.y, bPos.x, bPos.y);  
    if (dist <= rad) {  
        return true;  
    } else {  
        return false;  
    }  
}  
  
//--------------------------------------------------------------  
bool testApp::polyCurve(vector<ofPoint> &poly) {  
    /*  
     I found this formula on stack overflow. I'll be honest, I'm not   
     entirely sure how it works, but I'm sure glad it does. It's supposed  
     to work on concave polys (crescent moon shape) and even self crossing   
     polys (figure 8 shape).  
     */  
      
    float sum = 0;  
    for (int i=0; i<poly.size(); i++) {  
        if (i==0) {  
            sum += (poly[i].x - poly[poly.size()-1].x) * (poly[i].y + poly[poly.size()-1].y);  
        } else {  
            sum += (poly[i].x - poly[i-1].x) * (poly[i].y + poly[i-1].y);  
        }  
    }  
      
    if (sum > 0) {  
        return true;  
    }  
    if (sum < 0) {  
        return false;  
    }  
}  
  

Ball.h

  
  
//  
//  Ball.h  
//  iPadExample  
//  
//  Created by Lee Williams on 4/11/12.  
//  Copyright (c) 2012 none. All rights reserved.  
//  
  
#pragma once  
#include "ofMain.h"  
#include "ofxiPhone.h"  
#include "ofxiPhoneExtras.h"  
  
class Ball {  
      
public:  
    void setup();  
    void update();  
    void draw();  
      
    void touchDown(ofTouchEventArgs &touch);  
	void touchMoved(ofTouchEventArgs &touch);  
	void touchUp(ofTouchEventArgs &touch);  
	void touchDoubleTap(ofTouchEventArgs &touch);  
      
    ofPoint pos;  
    ofPoint vel;  
    bool active;  
    float speed;  
    float edge;  
    int radius;  
      
      
    ofPoint tempDir;  
};  
  

Ball.mm

  
  
//  
//  Ball.cpp  
//  iPadExample  
//  
//  Created by Lee Williams on 4/11/12.  
//  Copyright (c) 2012 none. All rights reserved.  
//  
  
#include "Ball.h"  
  
void Ball::setup() {  
    active = false;  
    pos.set(-100, -100);  
    radius = 10;  
    speed = 3;  
    edge = radius/speed;  
}  
  
//--------------------------------------------------------------  
void Ball::update() {  
    if (active) {  
        pos += vel;  
    }  
}  
  
//--------------------------------------------------------------  
void Ball::draw() {  
    if (active) {  
        ofPushStyle();  
        ofSetColor(0);  
        ofCircle(pos, radius);  
        ofSetColor(200, 200, 0);  
        ofLine(pos, pos + (vel*edge));  
        ofPopStyle();  
    }  
    else {  
        ofPushStyle();  
        ofNoFill();  
        ofSetLineWidth(2);  
        ofSetColor(0);  
        ofCircle(pos, radius);  
        ofLine(pos, tempDir);  
        ofPopStyle();  
    }  
}  
  
//--------------------------------------------------------------  
void Ball::touchDown(ofTouchEventArgs &touch) {  
    pos.set(touch.x, touch.y);  
    tempDir = pos;  
}  
  
//--------------------------------------------------------------  
void Ball::touchMoved(ofTouchEventArgs &touch) {  
    tempDir.set(touch.x, touch.y);  
}  
  
//--------------------------------------------------------------  
void Ball::touchUp(ofTouchEventArgs &touch) {  
    float angle = atan2(touch.y - pos.y, touch.x - pos.x);  
      
    vel.x = cos(angle) * speed;  
    vel.y = sin(angle) * speed;  
      
    active =  true;  
}