/*
	This heading must remain intact at all times.
	Copyright (c) 2009 Mark Mason. All rights reserved.

	File:	Q-Cogo-Sketch.js
	Use:	To provide sketching operations for Q-Cogo, <http://www.q-cogo.com/>.
	Ver:	1.1 (Beta)

	Created by Mark Mason. Latest version available from <http://www.q-cogo.com/>.



	This file is part of Q-Cogo.
	
	Q-Cogo is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.
	
	Q-Cogo is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License
	along with Q-Cogo.  If not, see <http://www.gnu.org/licenses/>.



	FUNCTION LISTING

	SketchArea
	SketchTransform
	SketchBrgBrg
	SketchPtLine
	SketchPtPt
	SketchPoints
	FindScale
	ImgCoord
	NorthArrow
	Points
	Labels
*/



// *******************************************************************************************************************************

function SketchArea(pointsMatrix, Canvas) {

// Sketches the most recent area operation of three or many points into the appropriate sketch area
// Input:  Points matrix, canvas to sketch
// Output: The updated sketch of the operation

// Find width and height of canvas; if not found, default to size of points canvas

	var Width = document.getElementsByTagName('div')[Canvas].offsetWidth;
	var Height = document.getElementsByTagName('div')[Canvas].offsetHeight;

// If a from point was provided, sketch point to point operation

	if (pointsMatrix != '') {

		var lP = pointsMatrix.length - 1;

// Form matrix of circle / curve points (top left and bottom right of circle / curve extents) and array of start and end angles

		var cM = new Array(0);
		var SEang = new Array(0);
		var cE = new Array(0);

		for (var i=0; i<lP; i++) {

			var indexM = ((i == 0) ? pointsMatrix.length - 2 : i - 1);

			if (pointsMatrix[i][0].search(/\*/) >= 0) {

				var R = PtPtInverse(0, pointsMatrix[i][0].replace(/\*/g,''), pointsMatrix[i + 1][0])[0];

// Total extents of circle containing curve, used for drawing curve

				cM[cM.length] = ['P', parseFloat(pointsMatrix[i][1]) + R, parseFloat(pointsMatrix[i][2]) - R, 0, 'D'];
				cM[cM.length] = ['P', parseFloat(pointsMatrix[i][1]) - R, parseFloat(pointsMatrix[i][2]) + R, 0, 'D'];

				var Ang1 = PtPtInverse(0, pointsMatrix[i][0].replace(/\*/g,''), pointsMatrix[i + 1][0])[2];
				var Ang2 = PtPtInverse(0, pointsMatrix[i][0].replace(/\*/g,''), pointsMatrix[indexM][0])[2];

				var Ang11 = Math.min((5 * Math.PI / 2 - Ang1) % (2 * Math.PI), (5 * Math.PI / 2 - Ang2) % (2 * Math.PI));
				var Ang22 = Math.max((5 * Math.PI / 2 - Ang1) % (2 * Math.PI), (5 * Math.PI / 2 - Ang2) % (2 * Math.PI));

// Start and end angles of curve

				if (pointsMatrix[i][0].search(/\*/) == 0) {

					SEang[SEang.length] = ((Ang22 - Ang11 < Math.PI) ? Ang22 : Ang11);
					SEang[SEang.length] = ((Ang22 - Ang11 < Math.PI) ? Ang11 : Ang22);

				}

				else {

					SEang[SEang.length] = ((Ang22 - Ang11 < Math.PI) ? Ang11 : Ang22);
					SEang[SEang.length] = ((Ang22 - Ang11 < Math.PI) ? Ang22 : Ang11);

				}

// Extents of curve only, used for finding appropriate scale for sketch

				Ang2 = SEang[SEang.length-1];
				Ang1 = SEang[SEang.length-2];
				var totAng = (Ang2 - Ang1 + 2 * Math.PI) % (2 * Math.PI);

				var Emax = (((Ang2 > 0 && Ang2 - totAng < 0) || (Ang1 < 360 && Ang1 + totAng > 360)) ? parseFloat(pointsMatrix[i][2]) + R : Math.max(parseFloat(pointsMatrix[indexM][2]), parseFloat(pointsMatrix[i + 1][2])));

				var Nmax = (((Ang2 > Math.PI / 2 && Ang2 - totAng < Math.PI / 2) || (Ang1 < Math.PI / 2 && Ang1 + totAng > Math.PI / 2)) ? parseFloat(pointsMatrix[i][1]) + R : Math.max(parseFloat(pointsMatrix[indexM][1]), parseFloat(pointsMatrix[i + 1][1])));

				var Emin = (((Ang2 > Math.PI && Ang2 - totAng < Math.PI) || (Ang1 < Math.PI && Ang1 + totAng > Math.PI)) ? parseFloat(pointsMatrix[i][2]) - R : Math.min(parseFloat(pointsMatrix[indexM][2]), parseFloat(pointsMatrix[i + 1][2])));

				var Nmin = (((Ang2 > Math.PI * 3 / 2 && Ang2 - totAng < Math.PI * 3 / 2) || (Ang1 < Math.PI * 3 / 2 && Ang1 + totAng > Math.PI * 3 / 2)) ? parseFloat(pointsMatrix[i][1]) - R : Math.min(parseFloat(pointsMatrix[indexM][1]), parseFloat(pointsMatrix[i + 1][1])));

				cE[cE.length] = ['P', Nmax, Emin, 0, 'D'];
				cE[cE.length] = ['P', Nmin, Emax, 0, 'D'];

			}

		}

		cM[cM.length] = [0];

// Find appropriate scale for sketch

		var Scale = FindScale(cE.concat(pointsMatrix), Width, Height)[0];
		var Xmax = FindScale(cE.concat(pointsMatrix), Width, Height)[1];
		var Xmin = FindScale(cE.concat(pointsMatrix), Width, Height)[2];
		var Ymax = FindScale(cE.concat(pointsMatrix), Width, Height)[3];
		var Ymin = FindScale(cE.concat(pointsMatrix), Width, Height)[4];

// Convert matrix of Northings and Eastings into matrix of X and Y image coordinates

		pointsMatrix = ImgCoord(pointsMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);
		cM = ImgCoord(cM, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 1);

// Get matrix of scenery points (all existing points)

		var sceneryMatrix = ParsePoints();
		sceneryMatrix = ImgCoord(sceneryMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);
		var lS = sceneryMatrix.length - 1;

// Sketch all points and labels (scenery points and labels in muted colour) and dashed line / curve between sequential points

		document.getElementById(Canvas).innerHTML = '';
		var jg = new jsGraphics(Canvas);

		Points(jg, sceneryMatrix, lS, '#999999');
		Labels(jg, sceneryMatrix, lS, Font.GREYBOX, '#999999');

		Points(jg, pointsMatrix, lP, '#000099');

		jg.setColor('#666666');
		jg.setStroke(Stroke.DOTTED);

		var indexC = 0;

		for (i=0; i<lP; i++) {

			if (pointsMatrix[i][0].search(/\*/) < 0 &&  pointsMatrix[i + 1][0].search(/\*/) < 0) {

				jg.drawLine(pointsMatrix[i][2] - 1, pointsMatrix[i][1] - 1, pointsMatrix[i + 1][2] - 1, pointsMatrix[i + 1][1] - 1);

			}

			else if (pointsMatrix[i][0].search(/\*/) >= 0) {

				var hwC = Math.abs(parseInt(cM[indexC][2]) - parseInt(cM[indexC + 1][2]));

				jg.drawEllipse(parseInt(cM[indexC][2]) - 1, parseInt(cM[indexC][1]) - 1, hwC, hwC, SEang[indexC], SEang[indexC + 1])

				indexC += 2;

			}

		}

		jg.setStroke(1);

		Labels(jg, pointsMatrix, lP, Font.BLUEBOX, '#000099');

	}

// If no points matrix was provided, note that there is no current area operation

	else {

		document.getElementById(Canvas).innerHTML = '';
		var jg = new jsGraphics(Canvas);

		jg.setFont('arial', '12px', Font.BOLD);
		jg.setColor('#666666');
		jg.drawStringRect('No Current Area', 0, Round(Height/2, 0) - 15, Width, 'center');

	}

// Draw North Arrow and scale bar

	NorthArrow(jg);
	ScaleBar(jg, Scale);

// Paint canvas

	jg.paint();

}

// *******************************************************************************************************************************

function SketchTransform(pointsMatrix, Canvas) {

// Sketches the most recent transformation into the appropriate sketch area
// Input:  Points matrix, canvas to sketch
// Output: The updated sketch of the operation

// Find width and height of canvas

	var Width = document.getElementsByTagName('div')[Canvas].offsetWidth;
	var Height = document.getElementsByTagName('div')[Canvas].offsetHeight;

// If a points matrix was provided, sketch intersection

	if (pointsMatrix != '') {

		var lP = pointsMatrix.length - 1;

// Find appropriate scale for sketch

		var Scale = FindScale(pointsMatrix, Width, Height)[0];
		var Xmax = FindScale(pointsMatrix, Width, Height)[1];
		var Xmin = FindScale(pointsMatrix, Width, Height)[2];
		var Ymax = FindScale(pointsMatrix, Width, Height)[3];
		var Ymin = FindScale(pointsMatrix, Width, Height)[4];

// Convert matrix of Northings and Eastings into matrix of X and Y image coordinates

		pointsMatrix = ImgCoord(pointsMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);

// Get matrix of scenery points (all existing points)

		var sceneryMatrix = ParsePoints();
		sceneryMatrix = ImgCoord(sceneryMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);
		var lS = sceneryMatrix.length - 1;

// Sketch all points and labels (scenery points and labels in muted colour) and appropriate lines between points

		document.getElementById(Canvas).innerHTML = '';
		var jg = new jsGraphics(Canvas);

		Points(jg, sceneryMatrix, lS, '#999999');
		Labels(jg, sceneryMatrix, lS, Font.GREYBOX, '#999999');

		jg.setColor('#cccccc');

		jg.drawLine(pointsMatrix[lP-4][2] - 1, pointsMatrix[lP-4][1] - 1, pointsMatrix[lP-3][2] - 1, pointsMatrix[lP-3][1] - 1);
		jg.drawLine(pointsMatrix[lP-3][2] - 1, pointsMatrix[lP-3][1] - 1, pointsMatrix[lP-1][2] - 1, pointsMatrix[lP-1][1] - 1);
		jg.drawLine(pointsMatrix[lP-1][2] - 1, pointsMatrix[lP-1][1] - 1, pointsMatrix[lP-2][2] - 1, pointsMatrix[lP-2][1] - 1);
		jg.drawLine(pointsMatrix[lP-2][2] - 1, pointsMatrix[lP-2][1] - 1, pointsMatrix[lP-4][2] - 1, pointsMatrix[lP-4][1] - 1);

		if (lP == 9) {

			jg.setColor('#bbbbbb');
			jg.drawLine(pointsMatrix[lP-4][2] - 5,  pointsMatrix[lP-4][1] - 5, pointsMatrix[lP-2][2] + 3, pointsMatrix[lP-2][1] + 3);
			jg.drawLine(pointsMatrix[lP-1][2] + 3,  pointsMatrix[lP-1][1] - 5, pointsMatrix[lP-3][2] - 5, pointsMatrix[lP-3][1] + 3);


		}

		jg.setColor('#666666');

		jg.drawLine(pointsMatrix[lP-8][2] - 1, pointsMatrix[lP-8][1] - 1, pointsMatrix[lP-7][2] - 1, pointsMatrix[lP-7][1] - 1);
		jg.drawLine(pointsMatrix[lP-7][2] - 1, pointsMatrix[lP-7][1] - 1, pointsMatrix[lP-5][2] - 1, pointsMatrix[lP-5][1] - 1);
		jg.drawLine(pointsMatrix[lP-5][2] - 1, pointsMatrix[lP-5][1] - 1, pointsMatrix[lP-6][2] - 1, pointsMatrix[lP-6][1] - 1);
		jg.drawLine(pointsMatrix[lP-6][2] - 1, pointsMatrix[lP-6][1] - 1, pointsMatrix[lP-8][2] - 1, pointsMatrix[lP-8][1] - 1);

		Points(jg, pointsMatrix, lP-8, '#000099');

		jg.setStroke(1);
	
		Labels(jg, pointsMatrix, lP-8, Font.BLUEBOX, '#000099');

	}

// If no points matrix was provided, note that there is no current transformation

	else {

		document.getElementById(Canvas).innerHTML = '';
		var jg = new jsGraphics(Canvas);

		jg.setFont('arial', '12px', Font.BOLD);
		jg.setColor('#666666');
		jg.drawStringRect('No Current Transformation', 0, Round(Height/2, 0) - 15, Width, 'center');

	}

// Draw North Arrow and scale bar

	NorthArrow(jg);
	ScaleBar(jg, Scale);

// Paint canvas

	jg.paint();

}

// *******************************************************************************************************************************

function SketchBrgBrg(pointsMatrix, Canvas) {

// Sketches the most recent bearing-bearing intersection into the appropriate sketch area
// Input:  Points matrix, canvas to sketch
// Output: The updated sketch of the operation

// Find width and height of canvas

	var Width = document.getElementsByTagName('div')[Canvas].offsetWidth;
	var Height = document.getElementsByTagName('div')[Canvas].offsetHeight;

// If a points matrix was provided, sketch intersection

	if (pointsMatrix != '') {

		var lP = pointsMatrix.length - 1;

// Find appropriate scale for sketch

		var Scale = FindScale(pointsMatrix, Width, Height)[0];
		var Xmax = FindScale(pointsMatrix, Width, Height)[1];
		var Xmin = FindScale(pointsMatrix, Width, Height)[2];
		var Ymax = FindScale(pointsMatrix, Width, Height)[3];
		var Ymin = FindScale(pointsMatrix, Width, Height)[4];

// Convert matrix of Northings and Eastings into matrix of X and Y image coordinates

		pointsMatrix = ImgCoord(pointsMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);

// Get matrix of scenery points (all existing points)

		var sceneryMatrix = ParsePoints();
		sceneryMatrix = ImgCoord(sceneryMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);
		var lS = sceneryMatrix.length - 1;

// Sketch all points and labels (scenery points and labels in muted colour) and dashed line between sequential points

		document.getElementById(Canvas).innerHTML = '';
		var jg = new jsGraphics(Canvas);

		Points(jg, sceneryMatrix, lS, '#999999');
		Labels(jg, sceneryMatrix, lS, Font.GREYBOX, '#999999');

		Points(jg, pointsMatrix, lP, '#000099');

		jg.setColor('#666666');
		jg.setStroke(Stroke.DOTTED);

		jg.drawLine(pointsMatrix[0][2] - 1, pointsMatrix[0][1] - 1, pointsMatrix[2][2] - 1, pointsMatrix[2][1] - 1);
		jg.drawLine(pointsMatrix[1][2] - 1, pointsMatrix[1][1] - 1, pointsMatrix[2][2] - 1, pointsMatrix[2][1] - 1);

		jg.setStroke(1);

		Labels(jg, pointsMatrix, lP, Font.BLUEBOX, '#000099');

	}

// If no points matrix was provided, note that there is no current intersection

	else {

		document.getElementById(Canvas).innerHTML = '';
		var jg = new jsGraphics(Canvas);

		jg.setFont('arial', '12px', Font.BOLD);
		jg.setColor('#666666');
		jg.drawStringRect('No Current Intersection', 0, Round(Height/2, 0) - 15, Width, 'center');

	}

// Draw North Arrow and scale bar

	NorthArrow(jg);
	ScaleBar(jg, Scale);

// Paint canvas

	jg.paint();

}

// *******************************************************************************************************************************

function SketchBrgDist(pointsMatrix, Canvas, TwoPoints, Line) {

// Sketches the most recent bearing-distance intersection into the appropriate sketch area
// Input:  Points matrix, canvas to sketch, two points flag (1 if both solutions are to be sketched), bearing line vector
// Output: The updated sketch of the operation

// Find width and height of canvas

	var Width = document.getElementsByTagName('div')[Canvas].offsetWidth;
	var Height = document.getElementsByTagName('div')[Canvas].offsetHeight;

	var lP = pointsMatrix.length - 1;

// Find appropriate scale for sketch

	var Scale = FindScale(pointsMatrix, Width, Height)[0];
	var Xmax = FindScale(pointsMatrix, Width, Height)[1];
	var Xmin = FindScale(pointsMatrix, Width, Height)[2];
	var Ymax = FindScale(pointsMatrix, Width, Height)[3];
	var Ymin = FindScale(pointsMatrix, Width, Height)[4];

// Convert matrix of Northings and Eastings into matrix of X and Y image coordinates

	pointsMatrix = ImgCoord(pointsMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);

// Get matrix of scenery points (all existing points)

	var sceneryMatrix = ParsePoints();
	sceneryMatrix = ImgCoord(sceneryMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);
	var lS = sceneryMatrix.length - 1;

// Sketch all points and labels (scenery points and labels in muted colour) and appropriate lines between points

	document.getElementById(Canvas).innerHTML = '';
	var jg = new jsGraphics(Canvas);

	Points(jg, sceneryMatrix, lS, '#999999');
	Labels(jg, sceneryMatrix, lS, Font.GREYBOX, '#999999');

	Points(jg, pointsMatrix, lP, '#000099');

	jg.setColor('#666666');
	jg.setStroke(Stroke.DOTTED);

	if (TwoPoints) {

		jg.drawLine(pointsMatrix[Line[0]][2] - 1, pointsMatrix[Line[0]][1] - 1, pointsMatrix[Line[1]][2] - 1, pointsMatrix[Line[1]][1] - 1);

		jg.setStroke(1);

		jg.drawLine(pointsMatrix[1][2] - 1, pointsMatrix[1][1] - 1, pointsMatrix[2][2] - 1, pointsMatrix[2][1] - 1);
		jg.drawLine(pointsMatrix[1][2] - 1, pointsMatrix[1][1] - 1, pointsMatrix[3][2] - 1, pointsMatrix[3][1] - 1);

	}

	else {

		jg.drawLine(pointsMatrix[0][2] - 1, pointsMatrix[0][1] - 1, pointsMatrix[2][2] - 1, pointsMatrix[2][1] - 1);

		jg.setStroke(1);

		jg.drawLine(pointsMatrix[1][2] - 1, pointsMatrix[1][1] - 1, pointsMatrix[2][2] - 1, pointsMatrix[2][1] - 1);

	}

	Labels(jg, pointsMatrix, lP, Font.BLUEBOX, '#000099');

// Draw North Arrow and scale bar

	NorthArrow(jg);
	ScaleBar(jg, Scale);

// Paint canvas

	jg.paint();

}

// *******************************************************************************************************************************

function SketchDistDist(pointsMatrix, Canvas, TwoPoints) {

// Sketches the most recent distance-distance intersection into the appropriate sketch area
// Input:  Points matrix, canvas to sketch, two points flag (1 if both solutions are to be sketched)
// Output: The updated sketch of the operation

// Find width and height of canvas

	var Width = document.getElementsByTagName('div')[Canvas].offsetWidth;
	var Height = document.getElementsByTagName('div')[Canvas].offsetHeight;

	var lP = pointsMatrix.length - 1;

// Find appropriate scale for sketch

	var Scale = FindScale(pointsMatrix, Width, Height)[0];
	var Xmax = FindScale(pointsMatrix, Width, Height)[1];
	var Xmin = FindScale(pointsMatrix, Width, Height)[2];
	var Ymax = FindScale(pointsMatrix, Width, Height)[3];
	var Ymin = FindScale(pointsMatrix, Width, Height)[4];

// Convert matrix of Northings and Eastings into matrix of X and Y image coordinates

	pointsMatrix = ImgCoord(pointsMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);

// Get matrix of scenery points (all existing points)

	var sceneryMatrix = ParsePoints();
	sceneryMatrix = ImgCoord(sceneryMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);
	var lS = sceneryMatrix.length - 1;

// Sketch all points and labels (scenery points and labels in muted colour) and appropriate lines between points

	document.getElementById(Canvas).innerHTML = '';
	var jg = new jsGraphics(Canvas);

	Points(jg, sceneryMatrix, lS, '#999999');
	Labels(jg, sceneryMatrix, lS, Font.GREYBOX, '#999999');

	Points(jg, pointsMatrix, lP, '#000099');

	jg.setColor('#666666');
	jg.setStroke(1);

	if (TwoPoints) {

		jg.drawLine(pointsMatrix[0][2] - 1, pointsMatrix[0][1] - 1, pointsMatrix[2][2] - 1, pointsMatrix[2][1] - 1);
		jg.drawLine(pointsMatrix[0][2] - 1, pointsMatrix[0][1] - 1, pointsMatrix[3][2] - 1, pointsMatrix[3][1] - 1);
		jg.drawLine(pointsMatrix[1][2] - 1, pointsMatrix[1][1] - 1, pointsMatrix[2][2] - 1, pointsMatrix[2][1] - 1);
		jg.drawLine(pointsMatrix[1][2] - 1, pointsMatrix[1][1] - 1, pointsMatrix[3][2] - 1, pointsMatrix[3][1] - 1);

	}

	else {

		jg.drawLine(pointsMatrix[0][2] - 1, pointsMatrix[0][1] - 1, pointsMatrix[2][2] - 1, pointsMatrix[2][1] - 1);
		jg.drawLine(pointsMatrix[1][2] - 1, pointsMatrix[1][1] - 1, pointsMatrix[2][2] - 1, pointsMatrix[2][1] - 1);

	}

	Labels(jg, pointsMatrix, lP, Font.BLUEBOX, '#000099');

// Draw North Arrow and scale bar

	NorthArrow(jg);
	ScaleBar(jg, Scale);

// Paint canvas

	jg.paint();

}

// *******************************************************************************************************************************

function SketchPtLine(pointsMatrix, Canvas, Line) {

// Sketches the most recent point to line operation into the appropriate sketch area
// Input:  Points matrix, canvas to sketch
// Output: The updated sketch of the operation

// Find width and height of canvas

	var Width = document.getElementsByTagName('div')[Canvas].offsetWidth;
	var Height = document.getElementsByTagName('div')[Canvas].offsetHeight;

	var lP = pointsMatrix.length - 1;

// Find appropriate scale for sketch

	var Scale = FindScale(pointsMatrix, Width, Height)[0];
	var Xmax = FindScale(pointsMatrix, Width, Height)[1];
	var Xmin = FindScale(pointsMatrix, Width, Height)[2];
	var Ymax = FindScale(pointsMatrix, Width, Height)[3];
	var Ymin = FindScale(pointsMatrix, Width, Height)[4];

// Convert matrix of Northings and Eastings into matrix of X and Y image coordinates

	pointsMatrix = ImgCoord(pointsMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);

// Get matrix of scenery points (all existing points)

	var sceneryMatrix = ParsePoints();
	sceneryMatrix = ImgCoord(sceneryMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);
	var lS = sceneryMatrix.length - 1;

// Make diminished matrix of points, excluding calc point

	var dimMatrix = [pointsMatrix[0], pointsMatrix[1], pointsMatrix[2], pointsMatrix[4]];

// Sketch all points and labels (scenery points and labels in muted colour) and lines between appropriate points

	document.getElementById(Canvas).innerHTML = '';
	var jg = new jsGraphics(Canvas);

	Points(jg, sceneryMatrix, lS, '#999999');
	Labels(jg, sceneryMatrix, lS, Font.GREYBOX, '#999999');

	Points(jg, dimMatrix, lP - 1, '#000099');

	jg.setColor('#666666');

	jg.fillRect(pointsMatrix[3][2] - 2, pointsMatrix[3][1] - 2, 3, 3);

	jg.setStroke(Stroke.DOTTED);

	jg.drawLine(pointsMatrix[Line[0]][2] - 1, pointsMatrix[Line[0]][1] - 1, pointsMatrix[Line[1]][2] - 1, pointsMatrix[Line[1]][1] - 1);
	jg.drawLine(pointsMatrix[2][2] - 1, pointsMatrix[2][1] - 1, pointsMatrix[3][2] - 1, pointsMatrix[3][1] - 1);

	jg.setStroke(1);

	Labels(jg, dimMatrix, lP - 1, Font.BLUEBOX, '#000099');

// Draw North Arrow and scale bar

	NorthArrow(jg);
	ScaleBar(jg, Scale);

// Paint canvas

	jg.paint();

}

// *******************************************************************************************************************************

function SketchPtPt(pointsMatrix, Canvas) {

// Sketches the most recent point to point operation of two or many points into the appropriate sketch area
// Input:  Points matrix, canvas to sketch
// Output: The updated sketch of the operation

// Find width and height of canvas

	var Width = document.getElementsByTagName('div')[Canvas].offsetWidth;
	var Height = document.getElementsByTagName('div')[Canvas].offsetHeight;

// If a from point was provided, sketch point to point operation

	if (pointsMatrix != '') {

		var lP = pointsMatrix.length - 1;

// Find appropriate scale for sketch

		var Scale = FindScale(pointsMatrix, Width, Height)[0];
		var Xmax = FindScale(pointsMatrix, Width, Height)[1];
		var Xmin = FindScale(pointsMatrix, Width, Height)[2];
		var Ymax = FindScale(pointsMatrix, Width, Height)[3];
		var Ymin = FindScale(pointsMatrix, Width, Height)[4];

// Convert matrix of Northings and Eastings into matrix of X and Y image coordinates

		pointsMatrix = ImgCoord(pointsMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);

// Get matrix of scenery points (all existing points)

		var sceneryMatrix = ParsePoints();
		sceneryMatrix = ImgCoord(sceneryMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);
		var lS = sceneryMatrix.length - 1;

// Sketch all points and labels (scenery points and labels in muted colour) and dashed line between sequential points

		document.getElementById(Canvas).innerHTML = '';
		var jg = new jsGraphics(Canvas);

		Points(jg, sceneryMatrix, lS, '#999999');
		Labels(jg, sceneryMatrix, lS, Font.GREYBOX, '#999999');

		Points(jg, pointsMatrix, lP, '#000099');

		jg.setColor('#666666');
		jg.setStroke(Stroke.DOTTED);

		for (var i=0; i<lP-1; i++) {

			jg.drawLine(pointsMatrix[i][2] - 1, pointsMatrix[i][1] - 1, pointsMatrix[i + 1][2] - 1, pointsMatrix[i + 1][1] - 1);

		}

		jg.setStroke(1);

		Labels(jg, pointsMatrix, lP, Font.BLUEBOX, '#000099');

	}

// If no points matrix was provided, note that there is no current point to point operation

	else {

		var IndX = Canvas.search(/Canvas/);
		var Oper = Canvas.substring(0, IndX);

		document.getElementById(Canvas).innerHTML = '';
		var jg = new jsGraphics(Canvas);

		jg.setFont('arial', '12px', Font.BOLD);
		jg.setColor('#666666');
		jg.drawStringRect('No Current ' + Oper, 0, Round(Height/2, 0) - 15, Width, 'center');

	}

// Draw North Arrow and scale bar

	NorthArrow(jg);
	ScaleBar(jg, Scale);

// Paint canvas

	jg.paint();

}

// *******************************************************************************************************************************

function SketchPoints() {

// Sketches the current points into the points sketch area
// Input:  None
// Output: The updated sketch of the points

// Parse the existing points file contents into a points matrix

	var pointsMatrix = ParsePoints();
	var lP = pointsMatrix.length - 1;
	
// Find appropriate scale for sketch

	var Canvas = 'PointsCanvas';
	var Width = document.getElementsByTagName('div')[Canvas].offsetWidth;
	var Height = document.getElementsByTagName('div')[Canvas].offsetHeight;

	var Scale = FindScale(pointsMatrix, Width, Height)[0];
	var Xmax = FindScale(pointsMatrix, Width, Height)[1];
	var Xmin = FindScale(pointsMatrix, Width, Height)[2];
	var Ymax = FindScale(pointsMatrix, Width, Height)[3];
	var Ymin = FindScale(pointsMatrix, Width, Height)[4];

// Convert matrix of Northings and Eastings into matrix of X and Y image coordinates

	pointsMatrix = ImgCoord(pointsMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, 0);

// Sketch points

	document.getElementById(Canvas).innerHTML = '';
	var jg = new jsGraphics(Canvas);

	Points(jg, pointsMatrix, lP, '#000099');
	Labels(jg, pointsMatrix, lP, Font.BLUEBOX, '#000099');

// If no current points exist, write this in the sketch area

	if (lP == 0) {

		jg.setFont('arial', '12px', Font.BOLD);
		jg.setColor('#666666');
		jg.drawStringRect('No Current Points', 0, Round(Height/2, 0) - 15, Width, 'center');

	}

// Draw North Arrow and scale bar

	NorthArrow(jg);
	ScaleBar(jg, Scale);

// Paint canvas

	jg.paint();

}

// *******************************************************************************************************************************

function FindScale(pointsMatrix, Width, Height) {

// Finds an appropriate scale for a given sketch using points matrix and the target div
// Input:  Points matrix and target canvas div
// Output: The maximum possible scale, max and min values for both northing and easting

// Subtract padding in both directions

	Width = Width - 132;
	Height = Height - 24;

// Find maximum range of northings and eastings

	var lP = pointsMatrix.length;

	var Ymax = -99999999999999999999999;
	var Xmax = -99999999999999999999999;
	var Ymin = 99999999999999999999999;
	var Xmin = 99999999999999999999999;

	for (var i=0; i<lP; i++) {

		if (parseFloat(pointsMatrix[i][1]) > Ymax) { Ymax = parseFloat(pointsMatrix[i][1]); }
		if (parseFloat(pointsMatrix[i][1]) < Ymin) { Ymin = parseFloat(pointsMatrix[i][1]); }
		if (parseFloat(pointsMatrix[i][2]) > Xmax) { Xmax = parseFloat(pointsMatrix[i][2]); }
		if (parseFloat(pointsMatrix[i][2]) < Xmin) { Xmin = parseFloat(pointsMatrix[i][2]); }

	}

	var RangeN = Ymax - Ymin;
	var RangeE = Xmax - Xmin;

// Calculate maximum scale in both directions

	var ScaleN = 99999999999999999999999;
	var ScaleE = 99999999999999999999999;

	if (RangeN) {

		ScaleN = Height / RangeN;

	}

	if (RangeE) {

		ScaleE = Width / RangeE;

	}

// Return the lowest of the maximum scales, so no points are beyond the div extents

	return[Math.min(ScaleE, ScaleN), Xmax, Xmin, Ymax, Ymin];

}

// *******************************************************************************************************************************

function ImgCoord(pointsMatrix, Scale, Xmax, Xmin, Ymax, Ymin, Width, Height, ForceAll) {

// Changes matrix of point northings and eastings into X and Y image coordinates
// Input:  Points matrix and the defined scale, max and min values for X and Y, width and height of target div, force all points flag (1 for no delete)
// Output: A matrix of X and Y image coordinates

// Find X and Y padding

	var PadX = (Width - (Xmax - Xmin) * Scale) / 2;
	var PadY = (Height - (Ymax - Ymin) * Scale) / 2;

// Convert northings and eastings to image coordinates

	var lP = pointsMatrix.length - 1;

	for (var i=0; i<lP; i++) {

		var Yval = Round((Ymax - parseFloat(pointsMatrix[i][1])) * Scale + PadY, 0);
		var Xval = Round((parseFloat(pointsMatrix[i][2]) - Xmin) * Scale + PadX, 0);

		if ((Yval < 12 || Yval > Height - 12 || Xval < 66 || Xval > Width - 66) && !ForceAll) {

			pointsMatrix.splice(i, 1);
			lP = lP - 1;
			i = i - 1;

		}

		else {

			pointsMatrix[i][1] = Yval;
			pointsMatrix[i][2] = Xval;

		}

	}

	return(pointsMatrix);

}

// *******************************************************************************************************************************

function NorthArrow(jg) {

// Draws a North arrow into the current open sketch at a fixed position
// Input:  The open graphics canvas object
// Output: The updated sketch, including the North arrow

	jg.setColor('#666666');
	jg.setFont('arial', '22px', Font.BOLD);
	jg.drawString('N', 23, 35);
	jg.setStroke(2);
	jg.drawLine(30, 35, 30, 20);
	jg.drawLine(30, 20, 37, 27);
	jg.drawLine(30, 20, 23, 27);

}

// *******************************************************************************************************************************

function ScaleBar(jg, Scale) {

// Draws scale bar into the current open sketch at a fixed position
// Input:  The open graphics canvas object
// Output: The updated sketch, including the scale bar, if drawing is at a sensible scale

	var BarWidth = 36;
	var Factor = Round(BarWidth / Scale, 2)

	if (Factor > 0) {

		jg.setFont('arial', '9px', Font.PLAIN);
		jg.setStroke(3);
		jg.drawLine(30 - BarWidth / 2, 90, 30 + BarWidth / 2, 90);
		jg.drawStringRect(Factor + '', 31 - (BarWidth + 20) / 2, 79, BarWidth + 20, 'center');

	}

}

// *******************************************************************************************************************************

function Points(jg, pointsMatrix, lP, Color) {

// Draws points into the open sketch
// Input:  The open graphics canvas object, the matrix of points to draw and its length, and the point color
// Output: The updated sketch, including the new points

	jg.setColor(Color);

	for (var i=0; i<lP; i++) {

		jg.fillRect(pointsMatrix[i][2] - 2, pointsMatrix[i][1] - 2, 3, 3);

	}

}

// *******************************************************************************************************************************

function Labels(jg, pointsMatrix, lP, fontStyle, Color) {

// Draws point labels into the open sketch
// Input:  The open graphics canvas object, the matrix of points to draw and its length, font style as defined in "wz_jsgraphics.js", font color
// Output: The updated sketch, including the new labels

	jg.setFont('monospace', '11px', fontStyle, Color);

	for (var i=0; i<lP; i++) {

		jg.setColor(Color);
		jg.drawString(pointsMatrix[i][0].replace(/\*/g,''), pointsMatrix[i][2] + 2, pointsMatrix[i][1] - 8);

	}

}

// *******************************************************************************************************************************
