<?php
/* Utility to take coordinates read from Genitizer graphics tablet (or any other suitable one) and map them to Ordnance Survey eastings and northings,
 * assuming one is using the tablet to digitise features off an Ordnance Survey map. It will also work for any other map coordinates that you have
 * provided they are linear over the map.
 * First three points must be calibration ones, aligned with OS grid (e.g. top-left, bottom-left, and bottom-right points) for which the OS eastings and northings are known
 * and can be entered into this program (see $r0, $r1, & $r2). Remaining points are entered into $pts array.
 * Outputs a long string of Javascript, giving the OS points in form: {x:123456, y:654321}, {...}...
 * Treats button 4 as a spacer, which is output as a javascript comment
 */   
class Point {
public $x;
public $y;
function __construct($x, $y) {
		$this->x = $x;
		$this->y = $y;
		}
}
// data points
$pts = array();
$buts = array(); // code for button pressed

// real world points to which calibration points should be mapped
$r0 = new Point(446000 ,122000);
$r1 = new Point(451000, 122000);
$r2 = new Point(446000, 118000);

$divider = 0;
$an = 0;
$bn = 0;
$cn = 0;
$dn = 0;
$en = 0;
$fn = 0;

// calculate affine transformation
function calc_affine() {
	global $c0,$c1,$c2; // calibration points in tablet coords
	global $r0,$r1,$r2; // calibration points in real world coords
	global $an,$bn,$cn,$dn,$en,$fn,$divider;

	$divider = (($c0->x - $c2->x) * ($c1->y - $c2->y)) - (($c1->x - $c2->x) * ($c0->y - $c2->y));
	if (abs($divider) < 0.000001) {
		echo "Divider is ZERO - check your calibration points";
		die();
		}
	$an = (($r0->x - $r2->x) * ($c1->y - $c2->y)) - (($r1->x - $r2->x) * ($c0->y - $c2->y));
	$bn = (($c0->x - $c2->x) * ($r1->x - $r2->x)) - (($r0->x - $r2->x) * ($c1->x - $c2->x));
	$cn = ($c2->x * $r1->x - $c1->x * $r2->x) * $c0->y + ($c0->x * $r2->x - $c2->x * $r0->x) * $c1->y + ($c1->x * $r0->x - $c0->x * $r1->x) * $c2->y;
	$dn = (($r0->y - $r2->y) * ($c1->y - $c2->y)) - (($r1->y - $r2->y) * ($c0->y - $c2->y));
	$en = (($c0->x - $c2->x) * ($r1->y - $r2->y)) - (($r0->y - $r2->y) * ($c1->x - $c2->x));
	$fn = ($c2->x * $r1->y - $c1->x * $r2->y) * $c0->y + ($c0->x * $r2->y - $c2->x * $r0->y) * $c1->y + ($c1->x * $r0->y - $c0->x * $r1->y) * $c2->y;
	}

// apply affine transformation
function mappoint($p) {
	global $an,$bn,$cn,$dn,$en,$fn,$divider;
	
	return new Point((($an * $p->x) + ($bn * $p->y) + $cn) / $divider, (($dn * $p->x) + ($en * $p->y) + $fn) / $divider);
	}

// main
$ifnam = 'gscoords.txt';
$fp = fopen($ifnam, 'r');
if (!$fp) {
	echo "Cannot open file $ifnam\n";
	die();
	}
while (($ar = fgetcsv($fp))) {
	$pts[] = new Point(intval($ar[0]), intval($ar[1]));
	$buts[] = intval($ar[2]);
	}
fclose($fp);
$c0 = $pts[0]; $c1 = $pts[1]; $c2 = $pts[2]; // first three points are calibrations 
calc_affine();
echo "divider=$divider, an=$an, bn=$bn, cn=$cn, dn=$dn, en=$en, fn=$fn\n";
$ar = array($c0, $c1, $c2);
foreach ($ar as $p) {
	$op = mappoint($p);
	echo "($p->x, $p->y) => ($op->x, $op->y)\n";
	}
$fp = fopen('coords.txt', 'w');
for ($j = 3; $j < count($pts); $j++) {
	if ($buts[$j] == 4) {
		fprintf($fp, " // spacer\n");
		continue;
		}
	$op = mappoint($pts[$j]);
	fprintf($fp, ', {x:' . round($op->x) . ', y:' . round($op->y) . '}');
	}
fprintf($fp, "\n"); fclose($fp);
echo "File 'coords.txt' written\n";	