function BufferedLine(radius, testLine) {
	var Buffer = new Array();

	function createBuffer(rad) {
		var PixelBuffer = new Array();
		var rad_sq = .71*rad; // Approximation for Sin(Pi*.25) or Sin(45-degrees)
		PixelBuffer[0] = new Array();
		PixelBuffer[0][0] = new Point(-1*rad_sq,-1*rad_sq);
		PixelBuffer[0][1] = new Point(0,-1*rad);
		PixelBuffer[0][2] = new Point(rad_sq, -1*rad_sq);

		PixelBuffer[1] = new Array();
		PixelBuffer[1][0] = new Point(-1*rad, 0);
		PixelBuffer[1][1] = new Point(0, 0);
		PixelBuffer[1][2] = new Point(rad, 0);

		PixelBuffer[2] = new Array();
		PixelBuffer[2][0] = new Point(-1*rad_sq, rad_sq);
		PixelBuffer[2][1] = new Point(0,rad);
		PixelBuffer[2][2] = new Point(rad_sq, rad_sq);

		for(var i = 0; i < testLine.length; i++) {
			for(x = 0; x < 3; x++) {
				for(y= 0; y < 3; y++) {
					var bufferPoint = PixelBuffer[x][y];
					bufferPoint = new Point(bufferPoint.x + testLine[i].x, bufferPoint.y + testLine[i].y);
					Buffer[Buffer.length] = bufferPoint;
				}
			}	
		}
		var log = document.getElementById('Coordinates');
		document.appendChild

	}

	var RoughBuffer = new Array();

	function createRoughBuffer(rad) {

		logDebugMessage('CRB',false,'Creating Segments...');
		for(var i = 1; i < testLine.length; i++) {
			var line = new LineSegment(testLine[i-1], testLine[i]);
			var segments = 3;

			var inc = line.getLength() / 2;

			var slope = line.slope();
			var baseY = Math.min(testLine[i-1].y, testLine[i].y);
			var baseX = Math.min(testLine[i-1].x, testLine[i].x);
			logDebugMessage('Create Rough Buffer', false, 'Segments: '+segments+' Line Length: '+line.getLength()+' Radius: '+rad);
			for(var x = 1; x < segments; x++) {
				var poly = new Circle();
				poly.Radius = rad;

				if(slope < 1 && slope > -1 && isFinite(slope)) {
					var newX = baseX +(x * inc);
					var newY = line.eval(newX);
					poly.Center = new Point(newX, newY);
				} else {
					var newY = baseY + (x*inc);
					poly.Center = new Point(baseX, newY);	
				}
				RoughBuffer[RoughBuffer.length] = poly;
			}
		}
	}

	function elimPoints(rad){
		createRoughBuffer(rad);
		var NewBuffer = new Array();
		for(var p = Buffer.length - 1; p >= 0; p--) {
			var bufferTest = false;
			for(var i = 0; i < RoughBuffer.length && !bufferTest; i++) {
				if(RoughBuffer[i].isMember(Buffer[p])) {
					bufferTest = true;
				}
			}
			if(bufferTest) {
				logDebugMessage('Elim', false, 'Elminated '+p);
			} else {
				NewBuffer[NewBuffer.length] = Buffer[p];
			}
		}

		logDebugMessage('Elim',true,'Buffer: '+Buffer.length);
		logDebugMessage('Elim',true,'New Buffer: '+NewBuffer.length);
		Buffer = NewBuffer;
	}



	function findNearest(P, Points) {

		if(!P) { logDebugMessage('Find Nearest', false, 'P is invalid'); }
		var nearestPoint = null;
		var min_len = 99999999;
		var test_len = 0;
		for(var i = 0; i < Points.length; i++) {
			if(!Points[i]) { logDebugMessage('Find Nearest', false, 'Points '+i+' is invalid'); }
			var cross = CrossesLine(P, Points[i]); 
			test_len = getPointDiff(P, Points[i]);
			if(!cross && test_len < min_len) {
				nearestPoint = 	i;
				min_len = test_len;
		//		logDebugMessage('Nearest',false,'Pick '+i+' '+cross);
			} else {
		//		logDebugMessage('Nearest',false,'Exclude '+i);
			}
		}	
		return nearestPoint;
	}


	function getPointDiff(A, B){
		var line = new LineSegment(A, B);
		return line.getLength();
	}

	function CrossesLine(A, B) {
		var tLine = new LineSegment(A,B);
		var c = 0;
		for(var i = 1; i < testLine.length; i++) {
			var line = new LineSegment(testLine[i-1], testLine[i]);
			if(line.intersects(tLine)) {
//				logDebugMessage('Cross', true, 'There is a cross!');
				return true;
			} 
			c++;
		}
//		logDebugMessage('Cross',true,'Miss');
		return false;
	}



	function orderPoints() {
		var BufferCopy = new Array();
		for(var i = 0; i < Buffer.length; i++) BufferCopy[i] = Buffer[i];

		var ordered = new Array();
		ordered[0] = BufferCopy[0];

		var i = 1;	
//		logDebugMessage('Order Points',false,'Buffer Copy Length: '+BufferCopy.length);
		while(BufferCopy.length > 1) {	
			var nextI = findNearest(ordered[ordered.length-1], BufferCopy);

//			logDebugMessage('Order Loop', false, 'Next I: '+nextI);
//			logDebugMessage('Order Loop', false, 'Next I V: '+BufferCopy[nextI].toString(','));

			ordered[ordered.length] = BufferCopy[nextI];

			var zeroElm = BufferCopy[0];
			BufferCopy[0] = BufferCopy[nextI];
			BufferCopy[nextI] = zeroElm;
			BufferCopy.shift();
			//plotPoint(ordered[ordered.length-1], 'order');
		}
		logDebugMessage('Order Points', false, 'Ordered Set Length: '+ordered.length);
		return ordered;
	}


	this.getBufferPolygon = function() {
		createBuffer2(radius);
		elimPoints2(radius-1);
		var polygon = new Polygon();
//		Buffer = orderPoints();
		return Buffer;
	}

/*
<input type="button" value="Update Display" onclick="displayLineCoordinates(document.getElementById('Coordinates'))"/>
<input type="button" value="Elim Points" onclick="elimPoints(24)"/>
<input type="button" value="Create Buffer" onclick="createBuffer(25)"/>
<input type="button" value="Display Buffer" onclick="renderBuffer()"/>
*/

function elimPoints2(rad){
	for(var test = 0; test < 1; test++) {
//	createRoughBuffer2(rad, (test == 1));
	createRoughBuffer3(rad);
	var NewBuffer = new Array();
	for(var p = Buffer.length - 1; p >= 0; p--) {
		var bufferTest = false;
		for(var i = 0; i < RoughBuffer.length && !bufferTest; i++) {
			if(RoughBuffer[i].isMember(Buffer[p])) {
				bufferTest = true;
			}
		}
		if(bufferTest) {
			logDebugMessage('Elim', false, 'Elminated '+p);
		} else {
			NewBuffer[NewBuffer.length] = Buffer[p];
		}
	}

	logDebugMessage('Elim',true,'Buffer: '+Buffer.length);
	logDebugMessage('Elim',true,'New Buffer: '+NewBuffer.length);
	Buffer = NewBuffer;
	}
}


function createRoughBuffer2(rad, testAngles) {
	for(var i = 1; i < testLine.length; i++) {
		var line = new LineSegment(testLine[i-1], testLine[i]);
		var segments = Math.ceil(line.getLength() / rad);
		var inc = line.getLength() / segments;

		var slope = line.slope();
		var baseY = Math.min(testLine[i-1].y, testLine[i].y);

		for(var x = 1; x < segments; x++) {

			var poly = new Circle();

			poly.Radius = rad;

			if(isFinite(slope)) {
				var newX = testLine[i-1].x +(x * inc);
				var newY = line.eval(newX);
				poly.Center = new Point(newX, newY);
			} else {
				var newY = baseY + (x*inc);
				poly.Center = new Point(testLine[i-1].x, newY);	
			}
			RoughBuffer[RoughBuffer.length] = poly;
			logDebugMessage('Create Rough', false, poly.Center.toString(',')+' '+poly.Radius);		
		}

		logDebugMessage('Create Rough', true, 'Created '+segments+' Buffers for Points: '+(i-1)+' '+i);
		logDebugMessage('Create Rough', true, 'A to B '+testLine[i-1].toString(',')+' '+testLine[i].toString(','));
	}
}

function createRoughBuffer3(rad) {
	for(var i = 1; i < testLine.length - 1; i++) {
		var poly = new Circle();
		poly.Radius = rad;
		poly.Center = testLine[i];
		RoughBuffer[RoughBuffer.length] = poly;
	}
}

function createBufferAround(point, rad) {
	var PixelBuffer = new Array();
	var rad_sq = .71*rad; // Approximation for Sin(Pi*.25) or Sin(45-degrees)
	PixelBuffer[0] = new Array();
	PixelBuffer[0][0] = new Point(-1*rad_sq,-1*rad_sq);
	PixelBuffer[0][1] = new Point(0,-1*rad);
	PixelBuffer[0][2] = new Point(rad_sq, -1*rad_sq);

	PixelBuffer[1] = new Array();
	PixelBuffer[1][0] = new Point(-1*rad, 0);
	PixelBuffer[1][1] = new Point(0, 0);
	PixelBuffer[1][2] = new Point(rad, 0);

	PixelBuffer[2] = new Array();
	PixelBuffer[2][0] = new Point(-1*rad_sq, rad_sq);
	PixelBuffer[2][1] = new Point(0,rad);
	PixelBuffer[2][2] = new Point(rad_sq, rad_sq);

	var i = point;
		for(x = 0; x < 3; x++) {
			for(y= 0; y < 3; y++) {
				var bufferPoint = PixelBuffer[x][y];
				bufferPoint = new Point(bufferPoint.x + testLine[i].x, bufferPoint.y + testLine[i].y);
				Buffer[Buffer.length] = bufferPoint;
			}
		}	
	var log = document.getElementById('Coordinates');

}


function createEndPoint(rad, point) {
	var start, end;
	if(point == testLine.length - 1) {
		start = point - 1;
		end = point;
	} else if(point == 0) {
		start = 0; end = 1;
	}

	var line = new LineSegment(testLine[start], testLine[end]);
	var slope = line.slope();
	var inverse_slope = -1 / slope;
	var testPoint = testLine[point];

	if(!isFinite(slope)) {
		if(testPoint.y > testLine[end].y) {
			Buffer[Buffer.length] = new Point(testPoint.x, testPoint.y + rad);
		} else {
			Buffer[Buffer.length] = new Point(testPoint.x, testPoint.y - rad);
		}
	} else if(!isFinite(inverse_slope)) {
		logDebugMessage('Create End Point', true, 'Point: '+point+' Infinite Inverse Slope');
		if(testPoint.x >= testLine[end].x) {
			Buffer[Buffer.length] = new Point(testPoint.x + rad, testPoint.y );
		} else {
			Buffer[Buffer.length] = new Point(testPoint.x - rad, testPoint.y );
		}

	} else {
		var theta = Math.atan(slope);

		var linePoint = testLine[point];
		var x = Math.cos(theta) * rad;
		var y = slope * x;
		var xOp = 1;
		var yOp = 1;

	
		if((testLine[start].x < testLine[end].x && point == 0) ||
			(testLine[start].x > testLine[end].x && point == testLine.length - 1)) {
			xOp = -1;
		}
		if((testLine[start].y < testLine[end].y && point == 0) ||
			(testLine[start].y > testLine[end].y && point == testLine.length - 1)) {
		}
		var testY = (testLine[start].y < testLine[end].y && slope < 0);

		if(point == testLine.length -1 && testY) {
			y = y * -1;
		}
		if(point == 0 && !testY) {
			y = y * -1;
		}

		if(point == testLine.length-1 && testLine[start].y > testLine[end].y && slope > 0) {
			y = y * -1;
		}

		if(point == 0 && testLine[start].y > testLine[end].y && slope > 0) {
			y = y * -1;
		}
		Buffer[Buffer.length] = new Point(linePoint.x + (x * xOp), linePoint.y + y);
	}
	logDebugMessage('Create End Point', true, 'Created End Point for: '+point+ ' '+Buffer[Buffer.length-1].toString(',')+' Slope: '+slope+' Inverse Slope: '+inverse_slope);
}

function createBuffer2(rad) {
	createEndPoint(rad, 0);
	createTangents(rad,0,true);
	createEndPoint(rad, testLine.length-1);
	createTangents(rad,1,false);

	createEndPoint(rad, 0);
}


function crossesLine(A, B, crossLine) {
	var line = new LineSegment(A,B);
	return (line.intersects(crossLine));
}

function createTangents(rad,dir,top) {
	var TempBuffer = new Array();
	for(var i = 0; i < testLine.length; i++) {
		var start = i - 1, end = i;
		if(i == 0) {
			start = i;
			end = i+1;
		}
		var line = new LineSegment(testLine[start], testLine[end]);
		var slope = line.slope();

		var nextLine;
		if(i > 0 && i < (testLine.length - 1)) {
			nextLine = new LineSegment(testLine[end], testLine[end+1]);
			var slopeLine = new LineSegment(testLine[start], testLine[end+1]);
			var xSL = slopeLine.slope();
			slope = xSL;
		}

		var inverse_slope = -1 / slope;

		if(!isFinite(slope) && isFinite(inverse_slope)) {
			var linePoint = testLine[i];
			var xOp = -1;
			if(!top) { xOp = 1; }
			logDebugMessage('Tangents',true,'Start Infinite for point: '+i);
			var insPoint = new Point(linePoint.x + rad * xOp, linePoint.y);
			if(i > 0 && crossesLine(insPoint, TempBuffer[TempBuffer.length - 1], line)) {
				xOp = xOp * -1;
				insPoint = new Point(linePoint.x + rad * xOp, linePoint.y);

			logDebugMessage('Tangents',true,'Cross Line');	
			}

			if(nextLine && crossesLine(insPoint, TempBuffer[TempBuffer.length - 1], nextLine)) {
				xOp = xOp * -1;
				insPoint = new Point(linePoint.x + rad * xOp, linePoint.y);

			logDebugMessage('Tangents',true,'Cross Next Line');	
			}


			TempBuffer[TempBuffer.length] = insPoint;

			logDebugMessage('Tangents',true,'Point: '+i+' Infinite '+insPoint.toString(','));
		} else if(!isFinite(inverse_slope)) {
			var linePoint = testLine[i];
			var yOp = 1;
			if(!top) { yOp = -1; }
			
			var insPoint = new Point(linePoint.x, linePoint.y + rad * yOp);
			if(i > 0 && crossesLine(insPoint, TempBuffer[TempBuffer.length - 1], line)) {
				yOp = yOp * -1;
				insPoint = new Point(linePoint.x, linePoint.y + rad * yOp);
			}

			var xNextLine = false;
			if(nextLine) xNextLine = crossesLine(insPoint, TempBuffer[TempBuffer.length - 1], nextLine);

			if(nextLine && xNextLine) {
				yOp = yOp * -1;
				insPoint = new Point(linePoint.x, linePoint.y + rad * yOp);
			}

			TempBuffer[TempBuffer.length] = insPoint;

			logDebugMessage('Tangents',true,'Point: '+i+' Infinite Inverse '+insPoint.toString(','));
		} else {

			var theta = Math.atan(inverse_slope);
			var x = Math.cos(theta) * rad;
			var y = Math.sin(theta) * rad;
			var linePoint = testLine[i];
			if(y < 0 && top || y > 0 && !top) { y = y * -1; x = x * -1; }	
			/** Line Cross Test **/
			var insPoint = new Point(linePoint.x + x, linePoint.y + y);
			var xLine  = false;
			if(i > 0) {
				xLine = crossesLine(insPoint, TempBuffer[TempBuffer.length - 1], line);
			}
			if(i > 0 && xLine) {
				y = y * -1; x = x * -1;
				insPoint = new Point(linePoint.x + x, linePoint.y + y);
				logDebugMessage('Tangents',true,'Point: '+i+' Crosses Line');
			}

			var xNextLine = false;
			if(nextLine) xNextLine = crossesLine(insPoint, TempBuffer[TempBuffer.length - 1], nextLine);

			if(nextLine && xNextLine) {
				y = y * -1; x = x * -1;
				insPoint = new Point(linePoint.x + x, linePoint.y + y);

				logDebugMessage('Tangents',true,'Point: '+i+' Crosses Next Line');
			}
//			if(!(xLine && xNextLine)) {
				TempBuffer[TempBuffer.length] = insPoint;
//			}

			logDebugMessage('Tangents',true,'Point: '+i+' Finite '+insPoint.toString(','));
		}
	}

	if(top) {
		for(var i = 0; i < TempBuffer.length; i++) {
			Buffer[Buffer.length] = TempBuffer[i];
		}
	} else {
		for(var i = TempBuffer.length - 1; i >= 0; i--) {
			Buffer[Buffer.length] = TempBuffer[i];
		}

	}

}




}
