<?PHP
set_time_limit(0); //suppress time-outs
/*
[Start: Program Information Header]
Name : Tube mapper
Purpose : ----
Syntax :
Version : 0.15
Date : 20.vii.2004
License : BSD
[End: Program Information Header]
[Start: Author Information Header]
Name : James D. Forrester
Name : Ed Sanders
[End: Author Information Header]
*/
header('Content-type: text/plain');
// POPULATE WITH MYSQL DATABASE DETAILS
$mysql_server = '';
$mysql_user = '';
$mysql_password = '';
$mysql_dbname = '';
$dbserverlink = mysql_connect($mysql_server,$mysql_user,$mysql_password) or die('Error connecting to database: '.mysql_error().'</body></html>');
mysql_select_db($mysql_dbname) or die('Error selecting database: '.mysql_error().'</body></html>');
// choose a zone limit...
$this_zone = 1;
// or a specific line (0 if using a zone)
$this_line = 0;
$width=900; $height=600;
/* Sizes I used for each line, chosen by trial and improvement */
switch($this_line)
{
case 1:
$width = 900;
$height = 600;
break;
case 2:
$width = 1200;
$height = 720;
break;
case 3:
$width = 1000;
$height = 570;
break;
case 4:
$width = 2000;
$height = 860;
break;
case 5:
$width = 320;
$height = 490;
break;
case 6:
$width = 1200;
$height = 350;
break;
case 7:
$width = 910;
$height = 580;
break;
case 8:
$width = 1280;
$height = 700;
break;
case 9:
$width = 580;
$height = 1000;
break;
case 10:
$width = 1000;
$height = 800;
break;
case 11:
$width = 470;
$height = 570;
break;
case 12:
$width = 300;
$height = 200;
break;
case 13:
$width = 800;
$height = 600;
break;
}
$header = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
id="svg2"
width="'.$width.'"
height="'.$height.'"
y="0.00000000"
x="0.00000000"
version="1.0">';
/*
== BR logo (non-free license) ==
<polygon id="rail" fill="red" stroke="none" transform="scale(0.5)"
points="5,0 12,0 21,4 29,4 29,7 21,7 14,11
29,11 29,14 14,14 23,18 16,18 7,14
0,14 0,11 7,11 14,7 0,7 0,4 14,4" />
*/
$header .= '
<defs>
<g transform="scale(0.2) translate(-186, -460)"
id="rail">
<rect
id="body"
style="fill:#808080;stroke:none;"
y="477.49323"
x="186.32202"
height="24.131897"
width="90.994476" />
<circle
id="boiler"
style="fill:#808080"
transform="translate(231.8686,481.5260)"
r="10" cy="0" cx="0" />
<circle
id="wheel1"
style="fill:#808080;stroke:#ffffff;stroke-width:3"
transform="translate(201.8686,503.5260)"
r="10" cy="0" cx="0" />
<circle
id="wheel2"
style="fill:#808080;stroke:#ffffff;stroke-width:3"
transform="translate(231.8686,503.5260)"
r="10" cy="0" cx="0" />
<circle
id="wheel3"
style="fill:#808080;stroke:#ffffff;stroke-width:3"
transform="translate(261.8686,503.5260)"
r="10" cy="0" cx="0" />
<rect
id="chimney"
style="fill:#808080;"
y="461.22095"
x="255.97266"
height="23.334524"
width="14.142136" />
<rect
id="cabin"
style="fill:none;stroke:#808080;stroke-width:4;"
y="462.04932" x="188.32202"
height="20" width="20" />
</g>
</defs>
<defs>
<circle id="intersection" cx="0" cy="0" r="4" style="fill: white; stroke: black; stroke-width: 1.5;" />
</defs>';
// NB: "latitude * 1.6" is to account for the approximate ratio of latitude to longitude
// around London. For larger maps, this will obviously require a proper projection function
// Calculate boundaries
if($this_zone)
{
$this_line_name = 'Zone '.$this_zone;
extract(mysql_fetch_assoc(mysql_query("
SELECT
MAX(longitude) - MIN(longitude) as long_diff, MAX(latitude*1.6) - MIN(latitude*1.6) as lat_diff,
MIN(longitude) as long_min, MIN(latitude*1.6) as lat_min
FROM stations
INNER JOIN links ON id=station1 OR id=station2
WHERE zone < $this_zone + 1")));
}
else
{
$this_line_name = mysql_result(mysql_query("SELECT name FROM routes WHERE line=$this_line"), 0);
extract(mysql_fetch_assoc(mysql_query("
SELECT
MAX(longitude) - MIN(longitude) as long_diff, MAX(latitude*1.6) - MIN(latitude*1.6) as lat_diff,
MIN(longitude) as long_min, MIN(latitude*1.6) as lat_min
FROM stations
INNER JOIN links ON id=station1 OR id=station2
WHERE line = $this_line")));
}
if($long_diff/$lat_diff > $width/$height)
{
$scale = ($width-100)/$long_diff;
}
else
{
$scale = ($height-100)/$lat_diff;
}
$lat_min -= (($height/$scale)-$lat_diff)/2;
$long_min -= (($width/$scale)-$long_diff)/2;
// Load stations into memory
$stations = array();
$query_handle = mysql_query("
SELECT id, longitude-$long_min as xpos, (latitude*1.6)-$lat_min as ypos, name, display_name, total_lines, rail, line
FROM stations
INNER JOIN links ON id=station1 OR id=station2") or die(mysql_error());
while($array = mysql_fetch_assoc($query_handle))
{
extract($array);
$xpos *= $scale;// $xpos += 50;
$ypos *= $scale;// $ypos += 50;
$ypos = $height - $ypos;
$stations[$id] = array('xpos' => $xpos, 'ypos' => $ypos, 'name' => $name, 'display_name' => $display_name, 'total_lines' => $total_lines, 'rail' => $rail, 'line' => $line);
}
// Load lines/routes into memory
$lines = array();
$query_handle = mysql_query("
SELECT * FROM routes") or die(mysql_error());
while($array = mysql_fetch_assoc($query_handle))
{
extract($array);
$lines[$line] = array('name' => $name, 'RR' => hexdec(substr($colour, 0, 2)), 'GG' => hexdec(substr($colour, 2, 2)), 'BB' => hexdec(substr($colour, 4, 2)), 'stripe' => $stripe, 'colour' => $colour);
}
//$query_handle = mysql_query("SELECT * FROM links WHERE line=$this_line") or die(mysql_error());
// Generate the line/route paths
$tangents = array();
$output_lines = '';
$output_stripes = '';
if($this_line == 11 or $this_zone)
{
$this_line = 11;
$route = find_path(11, 35, 274); //Victoria Line
draw_path();
}
if($this_line == 1 or $this_zone)
{
$this_line = 1;
$route = find_path(1, 114, 84); //Bakerloo Line
draw_path();
}
if($this_line == 3 or $this_zone)
{
$this_line = 3;
$route = find_path(3, 25, 25); //Circle Line
draw_path();
}
if($this_line == 7 or $this_zone)
{
$this_line = 7;
$route = find_path(7, 243, 247); //Jubille Line
draw_path();
}
if($this_line == 6 or $this_zone)
{
$this_line = 6;
$route = find_path(6, 15, 110); //Hammersmith & City Line
draw_path();
}
if($this_line == 12 or $this_zone)
{
$this_line = 12;
$route = array(279, 13); //Waterloo & City Line
draw_path();
}
/* Picadilly Line */
if($this_line == 10 or $this_zone)
{
$this_line = 10;
$route = find_path(10, 1, 57, array(73, 234)); //Acton Town to Cockfosters, not via Ealing Common or South Ealing
draw_path();
$route = find_path(10, 271, 1); //Uxbride to Acton Town
array_push($route, 265); //Following on to Turnham Green
draw_path(true);
$route = find_path(10, 116, 1, array(117, 118)); //Hatton Cross to Acton Town
array_push($route, 265); //Following on to Turnham Green
draw_path(true);
$route = find_path(10, 116, 116, array(132)); //Hatton Cross to Hatton Cross (Heathrow loop) not via Hounslow West
array_push($route, 132); //Following on to Hounslow West
draw_path(true);
}
/* Northern Line */
if($this_line == 9 or $this_zone)
{
$this_line = 9;
$route = find_path(9, 169, 121, array(165, 279, 170, 47)); //Morden to High Barnet not via Mill Hill East, Waterloo, Mornington Crescent or Chalk Farm
draw_path();
$route = find_path(9, 81, 40, array(139)); //Edgware to Camden Town not via Kentish Town
array_push($route, 170); //...to Mornington Crescent
array_push($route, 89); //...to Euston
$route = find_path(9, 277, 136, array(84), 89, $route); //...to Warren Street to Kennington not via Elephant & Catle
array_push($route, 191); //Following on to Oval
draw_path(true);
$route = array(165, 93, 77); //Mill Hill East to Finchley Central, following on to East Finchley
draw_path(true);
}
/* East London Line */
if($this_line == 5 or $this_zone)
{
$this_line = 5;
$route = find_path(5, 175, 228, array(174)); //New Cross Gate to Shoreditch not via New Cross
draw_path();
$route = array(174, 253, 41); //New Cross Gate to Shoreditch onto Canada Water not via New Cross
draw_path(true);
}
/* Central Line */
if($this_line == 2 or $this_zone)
{
$this_line = 2;
$route = find_path(2, 294, 88, array(286, 275, 215)); //West Ruislip to Epping not via West Acton, Wanstead or Roding Valley
draw_path();
$route = find_path(2, 72, 76, array(112)); //Ealing Broadway to East Acton (following on) not via Hanger Lane
draw_path(true);
$route = find_path(2, 301, 153, array(37, 241, 230)); //Woodford to Leyton (following on) not via Buckhurst Hill, South Woodford or Snaresbrook
draw_path(true);
}
/* District Line */
if($this_line == 4 or $this_zone)
{
$this_line = 4;
$route = find_path(4, 72, 267, array(108, 287, 138, 122)); //Ealing Broadway to Upminster not via Gunnersbury, West Brompton, Kensington or High Street Kensington
draw_path();
$route = find_path(4, 213, 265, array(52)); //Richmond to Turnham Green not via Chiswick Park
draw_path();
$route = find_path(4, 83, 299, array(138, 293, 99)); //Edgware Road to Wimbledon not via Kensington, West Kensington or Gloucester Road
draw_path();
$route = array(138, 74); //Kensignton to Earl's Court
draw_path();
}
/* Metropolitan Line */
if($this_line == 8 or $this_zone)
{
$this_line = 8;
$route = find_path(8, 271, 178, array(184)); //Uxbridge to Northwick Park (following on) not via North Harrow
draw_path(true);
$route = array(280, 62, 168, 179); //Watford to Croxley to Moor Park following on to Northwood
draw_path(true);
$route = array(50, 46); //Chesham to Chalfront & Latimer
draw_path();
$route = find_path(8, 6, 282, array(50, 62, 291)); //Amersham to Wembley Park not via Chesham, Croxley or West Harrow
$route = find_path(7, 172, 290, array(), 282, $route); //Neasden to West Hampstead on Jubilee line, for path following
$route = find_path(8, 94, 2, array(), 290, $route); //Finchley Road to Aldgate
draw_path();
}
/* DLR */
if($this_line == 13 or $this_zone)
{
$this_line = 13;
$route = find_path(13, 13, 19, array(4, 292, 304)); //Bank to Beckton not via All Saints or West India Quay or West Silvertown
draw_path();
$route = find_path(13, 152, 155, array(201)); //Lewisham to Limehouse (following on) not via Poplar
draw_path(true);
$route = find_path(13, 247, 42, array(284, 27)); //Stratford to Canary Wharf (following on) not via Westferry or Blackwall
draw_path(true);
$route = array(262, 225); //Tower Gateway to Shadwell
draw_path();
$route = array(307, 306, 305, 304, 43, 79); //King George V to Canning Town (following on)
draw_path(true);
}
$output_stations = '';
foreach($stations as $i => $station)
{
extract($station);
if(isset($tangents[$i]))
{
if($total_lines > 1 or $rail)
{
$output_stations .= plot_intersection($xpos, $ypos, $name);
}
else
{
$this_station = plot_station($xpos, $ypos, $i, $lines[$line]);
$output_lines .= $this_station[0];
$output_stripes .= $this_station[1];
}
$output_stations .= plot_stationname($xpos, $ypos, $name, $display_name, $rail);
}
}
$output = $header.'
<g id="lines">'.$output_lines.'
</g>';
if($stripe)
$output .= '
<g id="stripes">'.$output_stripes.'
</g>';
$output .= '
<g id="stations">'.$output_stations.'
</g>';
$output .= '
</svg>';
echo $output;
$file = fopen($this_line_name.'.svg', 'w+');
fwrite($file, $output);
fclose($file);
mysql_close($dbserverlink);
# --------------------------
function draw_path($follow_on = false)
{
global $output_lines, $output_stripes, $tangents, $stations, $route, $this_line, $lines;
$control_points = array();
for($i=0; $i<count($route); $i++)
{
if(!$i)
{
$dx = ($stations[$route[$i+1]]['xpos'] - $stations[$route[$i]]['xpos']);
$dy = ($stations[$route[$i+1]]['ypos'] - $stations[$route[$i]]['ypos']);
$cx = $stations[$route[$i]]['xpos'] + ($dx/3);
$cy = $stations[$route[$i]]['ypos'] + ($dy/3);
$tangents[$route[$i]] = $dy/$dx;
array_push($control_points, array('x' => $stations[$route[$i]]['xpos'], 'y' => $stations[$route[$i]]['ypos'])); #First station
array_push($control_points, array('x' => $cx, 'y' => $cy)); #First control point
}
else if($i+1 == count($route))
{
$dx = ($stations[$route[$i]]['xpos'] - $stations[$route[$i-1]]['xpos']);
$dy = ($stations[$route[$i]]['ypos'] - $stations[$route[$i-1]]['ypos']);
$cx = $stations[$route[$i]]['xpos'] - ($dx/3);
$cy = $stations[$route[$i]]['ypos'] - ($dy/3);
array_push($control_points, array('x' => $cx, 'y' => $cy)); #Last control point
array_push($control_points, array('x' => $stations[$route[$i]]['xpos'], 'y' => $stations[$route[$i]]['ypos'])); #Last station
$tangents[$route[$i]] = $dy/$dx;
}
else
{
$dx = ($stations[$route[$i+1]]['xpos'] - $stations[$route[$i-1]]['xpos']);
$dy = ($stations[$route[$i+1]]['ypos'] - $stations[$route[$i-1]]['ypos']);
$cx = $stations[$route[$i]]['xpos'] - ($dx/6);
$cy = $stations[$route[$i]]['ypos'] - ($dy/6);
array_push($control_points, array('x' => $cx, 'y' => $cy)); #Pre-station control point
array_push($control_points, array('x' => $stations[$route[$i]]['xpos'], 'y' => $stations[$route[$i]]['ypos'])); #Station
$tangents[$route[$i]] = $dy/$dx;
$cx = $stations[$route[$i]]['xpos'] + ($dx/6);
$cy = $stations[$route[$i]]['ypos'] + ($dy/6);
array_push($control_points, array('x' => $cx, 'y' => $cy)); #Post-station control point
}
}
extract($lines[$this_line]);
for($i=0; $i<count($control_points)-3; $i+=3)
{
if($follow_on and $i == count($control_points)-4)
break;
extract($control_points[$i], EXTR_PREFIX_ALL, 'st0');
extract($control_points[$i+1], EXTR_PREFIX_ALL, 'st1');
extract($control_points[$i+2], EXTR_PREFIX_ALL, 'st2');
extract($control_points[$i+3], EXTR_PREFIX_ALL, 'st3');
$end_line = false;
if(!$i or $i == count($control_points)-4)
$end_line = true;
$output_lines .= '
<path
d="M '.$st0_x.' '.$st0_y.' C '.$st1_x.' '.$st1_y.' '.$st2_x.' '.$st2_y.' '.$st3_x.' '.$st3_y.'"
style="stroke-width: 4.5; stroke: #'.$colour.'; fill: none;'.(!$end_line ? ' stroke-linecap: round;' : '').'" />';
if($stripe)
{
$output_stripes .= '
<path
d="M '.$st0_x.' '.$st0_y.' C '.$st1_x.' '.$st1_y.' '.$st2_x.' '.$st2_y.' '.$st3_x.' '.$st3_y.'"
style="stroke-width: 1.5; stroke: #'.$stripe.'; fill: none;'.(!$end_line ? ' stroke-linecap: round;' : '').'" />';
}
}
}
function find_path($line, $start, $end, $not_via = array(), $last_station = 0, $array = array(), $i=0)
{
array_push($array, $start);
$not_via_query = '';
if(count($not_via))
{
foreach($not_via as $not_via_station)
{
$not_via_query .= " AND (station1 <> $not_via_station AND station2 <> $not_via_station)";
}
}
$next_station = mysql_result(mysql_query("
SELECT (station1 + station2 - $start) AS next_station
FROM links
WHERE (station1 = $start OR station2 = $start)
AND (station1 <> $last_station AND station2 <> $last_station)
$not_via_query
AND line = $line"), 0);
if($next_station <> $end)
{
return find_path($line, $next_station, $end, $not_via, $start, $array, $i+1);
}
else
{
array_push($array, $end);
return $array;
}
}
function plot_intersection($xpos, $ypos, $name)
{
$name = htmlentities($name, ENT_QUOTES);
$output = '
<use id="'.$name.'" x="'.$xpos.'" y="'.$ypos.'" xlink:href="#intersection" />';
return $output;
}
function plot_station($xpos, $ypos, $i, $line)
{
global $tangents;
$output_stripes = '';
extract($line);
$ds = sqrt(1+$tangents[$i]*$tangents[$i]);
$dy = -1/$ds;
$dx = $tangents[$i]/$ds;
$output_lines = '
<line
x1="'.$xpos.'" y1="'.$ypos.'" x2="'.($xpos+(5*$dx)).'" y2="'.($ypos+(5*$dy)).'"
style="stroke-width: 4.5; stroke: #'.$colour.'; stroke-linecap: square;" />
<line
x1="'.$xpos.'" y1="'.$ypos.'" x2="'.($xpos-(5*$dx)).'" y2="'.($ypos-(5*$dy)).'"
style="stroke-width: 4.5; stroke: #'.$colour.'; stroke-linecap: square;" />';
if($stripe)
{
$output_stripes = '
<line
x1="'.$xpos.'" y1="'.$ypos.'" x2="'.($xpos+(5*$dx)).'" y2="'.($ypos+(5*$dy)).'"
style="stroke-width: 1.5; stroke: #'.$stripe.'; stroke-linecap: square;" />
<line
x1="'.$xpos.'" y1="'.$ypos.'" x2="'.($xpos-(5*$dx)).'" y2="'.($ypos-(5*$dy)).'"
style="stroke-width: 1.5; stroke: #'.$stripe.'; stroke-linecap: square;" />';
# $dy = $tangents[$i]/$ds;
# $dx = 1/$ds;
# $output .= '
# <line
# x1="'.($xpos-(2.25*$dx)).'" y1="'.($ypos-(2.25*$dy)).'" x2="'.($xpos+(2.25*$dx)).'" y2="'.($ypos+(2.25*$dy)).'"
# style="stroke-width: 1.5; stroke: #'.$stripe.'; stroke-linecap: square;" />';
}
return array($output_lines, $output_stripes);
}
function plot_stationname($xpos, $ypos, $name, $display_name, $rail)
{
$name = htmlentities($name, ENT_QUOTES);
$lines = split('<br />', ($display_name ? $display_name : $name));
$output = '';
$output .= '
<text x="'.($xpos+7).'" y="'.$ypos.'" style="font-family: Verdana; font-size: 11px;">';
foreach($lines as $line)
{
$output .= '
<tspan x="'.($xpos+7).'" y="'.($ypos+4).'">'.htmlentities($line, ENT_QUOTES).'</tspan>';
$ypos += 12;
}
$output .= '
</text>';
if($rail)
$output .= '
<use x="'.($xpos+40).'" y="'.($ypos-16).'" xlink:href="#rail" />';
return $output;
}
?>