Files
pmgr/site/controllers/maps_controller.php
abijah 684f02ebc5 More tweaks to get the map working. At the moment, the clickable area is off because it's not scaled like the actual image is. I'll have to work on that next.
git-svn-id: file:///svn-source/pmgr/branches/initial_20090526@34 97e9348a-65ac-dc4b-aefc-98561f571b83
2009-05-29 03:36:28 +00:00

260 lines
9.8 KiB
PHP

<?php
class MapsController extends AppController {
var $helpers = array('Html');
/**************************************************************************
**************************************************************************
**************************************************************************
* action: index
* - Generates a list of all site maps
*
* REVISIT <AP> 20090528:
* We'll need to present only those site area maps that correspond
* to the users particular site.
*/
function index() {
$this->Map->recursive = 0;
$this->set('maps', $this->paginate());
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: view
* - Generates a site map page
*/
function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
$this->set('info', $this->mapInfo($id));
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: map
* - Produces a PNG site map image
*/
function map($id = null, $requested_width = 800) {
if (!$id) {
$this->Session->setFlash(__('Invalid Item.', true));
$this->redirect(array('action'=>'index'));
}
$this->image($this->mapInfo($id), $requested_width);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* mapInfo
*/
function mapInfo($id) {
// Set up array to hold the map information
$info = array('extents' => array(), 'units' => array(),
'map_id' => $id, 'border' => true);
/* // Find all of the map/unit information from this SiteArea */
/* $this->Map->SiteArea->recursive = 3; */
/* $this->Map->SiteArea->Site->unbindModel(array('hasMany' => array('SiteArea'))); */
/* $this->Map->unbindModel(array('belongsTo' => array('SiteArea'))); */
/* $map = $this->Map->SiteArea->read(null, $site_area_id); */
// Find all of the map/unit information from this SiteArea
$this->Map->recursive = 2;
$this->Map->SiteArea->unbindModel(array('hasOne' => array('Map')));
$map = $this->Map->read(null, $id);
//pr($map);
// Get the overall site limits, and then compute the
// actual boundary extents, adjusting for a border
$top_adjustment = 5;
$left_adjustment = 5;
$info['extents']['top'] = 0;
$info['extents']['left'] = 0;
$info['extents']['bottom'] = $top_adjustment + $map['Map']['depth'] + 5;
$info['extents']['right'] = $left_adjustment + $map['Map']['width'] + 5;
// Go through each unit in the map, calculating the map location
foreach ($map['Unit'] AS $unit) {
$lft = $unit['MapsUnit']['pt_left'] + $left_adjustment;
$top = $unit['MapsUnit']['pt_top'] + $top_adjustment;
$width =
$unit['MapsUnit']['transpose']
? $unit['UnitSize']['depth']
: $unit['UnitSize']['width'];
$depth =
$unit['MapsUnit']['transpose']
? $unit['UnitSize']['width']
: $unit['UnitSize']['depth'];
$info['units'][$unit['id']] =
array( 'id' => $unit['id'],
'name' => $unit['name'],
'left' => $lft,
'right' => $lft + $width,
'top' => $top,
'bottom' => $top + $depth,
'width' => $width,
'depth' => $depth,
'n-s' => $unit['MapsUnit']['transpose'] ? 0 : 1,
'status' => $unit['status']
);
}
//pr($info);
return $info;
}
// Temporary function
function unitStatusList() {
return
array('DELETED' => array(),
'DAMAGED' => array(),
'COMPANY' => array(),
'UNAVAILABLE' => array(),
'RESERVED' => array(),
'DIRTY' => array(),
'VACANT' => array(),
'OCCUPIED' => array(),
'LATE' => array(),
'LOCKED' => array(),
'LIENED' => array(),
);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* action: legend
* - Produces a PNG color legend image
*/
function legend($id = null, $requested_width = 400) {
$status = $this->unitStatusList();
$cols = 6;
$rows = (int)((count($status) + $cols - 1) / $cols);
$info = array('extents' => array(), 'units' => array(), 'legend' => array());
$info['legend']['width'] = 360;
$info['legend']['depth'] = 120;
$info['extents']['right'] = $info['legend']['width'] * $cols;
$info['extents']['bottom'] = $info['legend']['depth'] * $rows;
$top = $lft = 0;
foreach ($status AS $code => $color) {
$info['units'][] = array('name' => $code,
'status' => $code,
'width' => $info['legend']['width'],
'depth' => $info['legend']['depth'],
'left' => $lft,
'right' => $lft + $info['legend']['width'],
'top' => $top,
'bottom' => $top + $info['legend']['depth']);
$top += $info['legend']['depth'];
if ($top >= $info['legend']['depth'] * $rows) {
$top = 0; $lft += $info['legend']['width'];
}
}
$this->image($info, $requested_width, true);
}
/**************************************************************************
**************************************************************************
**************************************************************************
* helper: image
* - used by actions map & legend to set up unit information and
* color palates before rendering the PNG image.
*/
function image($info, $requested_width, $legend = false) {
//var $helpers = array('Html', 'Form', 'Javascript', 'Graph');
$this->layout = null;
$this->autoLayout = false;
Configure::write('debug', '0');
// Define our color palate
// REVISIT <AP>: 20090513
// Get colors from DB option tables
$info['palate']['main']['layout']['bg'] = array('red' => 255, 'green' => 255, 'blue' => 255);
$info['palate']['main']['layout']['border'] = array('red' => 192, 'green' => 192, 'blue' => 192);
$info['palate']['main']['layout']['wall'] = array('red' => 0, 'green' => 0, 'blue' => 0);
$info['palate']['unit']['DELETED']['bg'] = array('red' => 0, 'green' => 0, 'blue' => 0);
$info['palate']['unit']['DAMAGED']['bg'] = array('red' => 192, 'green' => 128, 'blue' => 128);
$info['palate']['unit']['COMPANY']['bg'] = array('red' => 128, 'green' => 192, 'blue' => 128);
$info['palate']['unit']['UNAVAILABLE']['bg'] = array('red' => 128, 'green' => 128, 'blue' => 192);
$info['palate']['unit']['RESERVED']['bg'] = array('red' => 192, 'green' => 192, 'blue' => 128);
$info['palate']['unit']['DIRTY']['bg'] = array('red' => 128, 'green' => 192, 'blue' => 192);
$info['palate']['unit']['VACANT']['bg'] = array('red' => 0, 'green' => 255, 'blue' => 128);
$info['palate']['unit']['OCCUPIED']['bg'] = array('red' => 0, 'green' => 128, 'blue' => 255);
$info['palate']['unit']['LATE']['bg'] = array('red' => 255, 'green' => 64, 'blue' => 64);
$info['palate']['unit']['LOCKED']['bg'] = array('red' => 255, 'green' => 128, 'blue' => 128);
$info['palate']['unit']['LIENED']['bg'] = array('red' => 255, 'green' => 192, 'blue' => 192);
// Determine text color to go with each background
foreach ($info['palate']['unit'] AS &$code) {
$component = $code['bg'];
$method = 3;
if ($method == 1) {
foreach (array('red', 'green', 'blue') AS $prim)
$component[$prim] = 255 - $component[$prim];
} elseif ($method == 2) {
foreach (array('red', 'green', 'blue') AS $prim)
$component[$prim] = ($component[$prim]) >= 128 ? 0 : 255;
} elseif ($method == 3) {
$val = (sqrt(pow($component['red'], 2) +
pow($component['green'], 2) +
pow($component['blue'], 2)) >= sqrt(3) * 128) ? 0 : 255;
foreach (array('red', 'green', 'blue') AS $prim)
$component[$prim] = $val;
}
$code['fg'] = $component;
}
//pr($info);
/*****
* The preference would be to leave all things "screen" related
* to reside in the view. However, two separate views need this
* information. The 'view' needs it to include a clickable map
* that corresponds to the map image, and of course, the 'map'
* (or 'image') view needs it to render the image. So, in the
* controller for now, unless I come up with a better idea.
*****/
// Scale things according to desired display width
$screen_adjustment_factor = $requested_width / $info['extents']['right'];
// Define image size
$info['width'] = $info['extents']['right'] * $screen_adjustment_factor;
$info['depth'] = $info['extents']['bottom'] * $screen_adjustment_factor;
// Go through each unit, adjusting map locations
foreach ($info['units'] AS &$unit) {
$unit['left'] *= $screen_adjustment_factor;
$unit['right'] *= $screen_adjustment_factor;
$unit['top'] *= $screen_adjustment_factor;
$unit['bottom'] *= $screen_adjustment_factor;
}
$this->set(compact('info'));
$this->render('image');
}
}
?>