var Camera = Class.create({
	/*
	 * Creates a new instance of this class with the given parameters.
	 * 
	 * width: the width of the camera sensor, in pixels.
	 * height: the height of the camera sensor, in pixels.
	 * focalLength: the focal length of the camera lens, in pixels.
	 * bearing_nominal: the nominal bearing aim point of the camera, in degrees.
	 * bearing_error: the bearing aim point error (from nominal), in degrees.
	 * elevation_error: the elevation aim point error (from level), in degrees.
	 * rotation_error: the rotation error about the aim point (from level), in degrees (positive means right side higher).
	 * distortion: the barrel distortion factor (1 = no distortion, < 1 = pincushion, > 1 = barrel).
	 */
	initialize: function(width, height, focalLength, bearing_nominal, bearing_error, elevation_error, rotation_error, distortion) {
		this.width = width;
		this.height = height;
		this.focalLength = focalLength; 
		this.bearing_nominal = bearing_nominal;
		this.bearing_error = bearing_error;
		this.elevation_error = elevation_error;
		this.rotation_error = rotation_error;
		this.distortion = distortion;
		this.features = [];
		this.center_x = (this.width - 1)/2.0;
		this.center_y = (this.height - 1)/2.0;
	},
	
	/*
	 * Given an offset on the camera image, returns the bearing in degrees.
	 */
	bearing: function(offset) {
		var sensor_deflection_px = Math.sqrt(Math.pow(offset.x - this.center_x,2) + Math.pow(offset.y - this.center_y,2));
		var sensor_deflection_rad = Math.atan(sensor_deflection_px / this.focalLength);
		var camera_deflection_rad = this.distortion * sensor_deflection_rad;
		var camera_polar_rad = this.signum(offset.x - this.center_x) * Math.acos(-(offset.y - this.center_y) / sensor_deflection_px);
		var corrected_camera_polar_rad = camera_polar_rad - this.toRadians(this.rotation_error);
		var bearing_rad = Math.asin(Math.sin(camera_deflection_rad) * Math.sin(corrected_camera_polar_rad) / Math.sin(this.rightAngle()));
		var corrected_bearing_deg = this.toDegrees(bearing_rad) + this.bearing_nominal + this.bearing_error;
		return (360.0 + corrected_bearing_deg) % 360;
	},
	
	signum: function(x) {
		return (x < 0) ? -1 : ((x > 0) ? 1 : 0);
	},
	
	toRadians: function(degrees) {
		return Math.PI * degrees / 180.0;
	},
	
	toDegrees: function(radians) {
		return 180.0 * radians / Math.PI;
	},
	
	rightAngle: function() {
		return this.toRadians(90);
	},
	
	addFeature: function(feat) {
		this.features.push(feat);
	},
	
	sortFeatures: function() {
		this.features.sort(function(a,b) {return a.distance - b.distance;});
	},
	
	findFeature: function(offset) {
		for (var i = 0; i < this.features.length; i++) {
			var feat = this.features[i];
			if (feat.poly.contains(offset))
				return feat;
		}
		return null;
	},
	
	type: 'Camera'
});