2
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
* ImgIndex Class definition
10
* @author Keith Hughitt <keith.hughitt@nasa.gov>
11
* @author Patrick Schmiedel <patrick.schmiedel@gmx.net>
12
* @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
13
* @link http://launchpad.net/helioviewer.org
16
* Provides methods for interacting with a JPEG 2000 archive.
19
* @package Helioviewer
20
* @author Keith Hughitt <keith.hughitt@nasa.gov>
21
* @author Patrick Schmiedel <patrick.schmiedel@gmx.net>
22
* @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
23
* @link http://launchpad.net/helioviewer.org
25
class Database_ImgIndex
27
private $_dbConnection;
30
* Creates an ImgIndex instance
34
public function __construct()
36
include_once 'DbConnection.php';
37
$this->_dbConnection = new Database_DbConnection();
41
* Adds a new screenshot entry to the database and returns its identifier
43
* @return int identifier for the screenshot
45
public function insertScreenshot($date, $scale, $roi, $watermark, $layers, $bitmask, $numLayers)
47
include_once 'src/Helper/DateTimeConversions.php';
49
// Add to screenshots table and get an id
50
$sql = sprintf("INSERT INTO screenshots VALUES(NULL, NULL, '%s', %f, PolygonFromText('%s'), %b, '%s', %d, %d);",
51
isoDateToMySQL($date),
60
$this->_dbConnection->query($sql);
62
return $this->_dbConnection->getInsertId();
66
* Returns a single movie entry
68
* @return string The movie information
70
public function getMovieInformation($id)
72
$sql = "SELECT *, AsText(regionOfInterest) as roi FROM movies " .
73
"LEFT JOIN movieFormats ON movies.id = movieFormats.movieId " .
74
"WHERE movies.id=$id AND movieFormats.format='mp4'";
75
return mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
79
* Updates movie entry with new information
83
public function storeMovieProperties($id, $startDate, $endDate, $numFrames, $frameRate, $length, $width, $height)
85
// Update movies table
88
SET startDate='%s', endDate='%s', numFrames=%f, frameRate=%f, movieLength=%f, width=%d, height=%d
90
$startDate, $endDate, $numFrames, $frameRate, $length, $width, $height, $id
92
$this->_dbConnection->query($sql);
96
* Updated movie entry to include processing start and end times
98
public function finishedBuildingMovieFrames($id, $buildTimeStart, $buildTimeEnd)
100
$sql = "UPDATE movies SET buildTimeStart='$buildTimeStart', buildTimeEnd='$buildTimeEnd' WHERE id=$id";
101
$this->_dbConnection->query($sql);
105
* Updates movie entry and marks it as "processing"
107
* @param $id int Movie identifier
108
* @param $format string Format being processed
112
public function markMovieAsProcessing($id, $format)
114
$sql = "UPDATE movieFormats SET status=1 WHERE movieId=$id AND format='$format'";
115
$this->_dbConnection->query($sql);
119
* Updates movie entry and marks it as being "finished"
121
* @param $id int Movie identifier
122
* @param $format string Format being processed
123
* @param $procTime int Number of seconds it took to encode the movie
125
public function markMovieAsFinished($id, $format, $procTime)
127
$sql = "UPDATE movieFormats SET status=2, procTime=$procTime " .
128
"WHERE movieId=$id AND format='$format'";
129
$this->_dbConnection->query($sql);
133
* Updates movie entry and marks it as being "finished"
135
public function markMovieAsInvalid($id)
137
$this->_dbConnection->query("UPDATE movieFormats SET status=3, procTime=NULL WHERE movieId=$id");
141
* Returns the information associated with the screenshot with the specified id
145
public function getScreenshot($id)
147
$sql = "SELECT * FROM screenshots WHERE id=$id";
148
return mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
152
* Takes an image filepath and returns some useful image information
154
public function getImageInformation($id) {
155
$sql = "SELECT * FROM images WHERE id=$id;";
158
$image = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
159
$image['sourceId'] = (int) $image['sourceId'];
162
$file = HV_JP2_DIR . $image["filepath"] . "/" .$image["filename"];
163
$xmlBox = $this->extractJP2MetaInfo($file);
166
$datasource = $this->getDatasourceInformationFromSourceId($image['sourceId']);
168
return array_merge($image, $xmlBox, $datasource);
172
* Finds the closest available image to the requested one, and returns information from
173
* database and XML box.
175
* @param string $date A UTC date string of the form "2003-10-05T00:00:00Z."
176
* @param int $sourceId An identifier specifying the image type or source requested.
178
* @return array Information about the image match including it's location, time, scale, and dimensions.
180
public function getClosestImage($date, $sourceId)
182
$img = $this->getImageFromDatabase($date, $sourceId);
183
$filename = HV_JP2_DIR . $img["filepath"] . "/" .$img["filename"];
184
$xmlBox = $this->extractJP2MetaInfo($filename);
186
return array_merge($img, $xmlBox);
190
* Queries database and finds the best matching image.
192
* @param string $date A UTC date string of the form "2003-10-05T00:00:00Z."
193
* @param int $sourceId An identifier specifying the image type or source requested.
195
* @return array Array including the image id, filepath, filename, date, and sourceId.
197
public function getImageFromDatabase($date, $sourceId)
199
include_once 'src/Helper/DateTimeConversions.php';
201
$datestr = isoDateToMySQL($date);
204
"( SELECT id, filepath, filename, date
209
ORDER BY date DESC LIMIT 1 )
211
( SELECT id, filepath, filename, date
216
ORDER BY date ASC LIMIT 1 )
217
ORDER BY ABS(TIMESTAMPDIFF(MICROSECOND, date, '%s')
219
$sourceId, $datestr, $sourceId, $datestr, $datestr
223
$result = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
225
// Make sure match was found
226
if (is_null($result)) {
227
$source = $this->_getDataSourceName($sourceId);
228
throw new Exception("No images of the requested type ($source) are currently available.");
231
// Cast id to integer
232
$result['id'] = (int) $result['id'];
238
* Queries the database and returns the closest image match before or equal to the date specified
240
* @param string $date A UTC date string of the form "2003-10-05T00:00:00Z."
241
* @param int $sourceId An identifier specifying the image type or source requested.
243
* @return array Array including the image id, filepath, filename, date, and sourceId.
245
public function getClosestImageBeforeDate($date, $sourceId)
247
include_once 'src/Helper/DateTimeConversions.php';
249
$datestr = isoDateToMySQL($date);
252
$sql = sprintf("SELECT filepath, filename, date FROM images WHERE sourceId = %d AND date <= '%s' ORDER BY date DESC LIMIT 1;", $sourceId, $datestr);
253
$img = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
255
// Make sure match was founds
257
$source = $this->_getDataSourceName($sourceId);
258
throw new Exception("No $source images are available on or before $date.");
265
* Queries the database and returns the closest image match after or equal to the date specified
267
* @param string $date A UTC date string of the form "2003-10-05T00:00:00Z."
268
* @param int $sourceId An identifier specifying the image type or source requested.
270
* @return array Array including the image id, filepath, filename, date, and sourceId.
272
public function getClosestImageAfterDate ($date, $sourceId)
274
include_once 'src/Helper/DateTimeConversions.php';
276
$datestr = isoDateToMySQL($date);
279
$sql = sprintf("SELECT filepath, filename, date FROM images WHERE sourceId = %d AND date >= '%s' ORDER BY date ASC LIMIT 1;", $sourceId, $datestr);
280
$img = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
282
// Make sure match was found
284
$source = $this->_getDataSourceName($sourceId);
285
throw new Exception("No $source images are available on or after $date.");
292
* Gets the human-readable name associated with the specified source id
294
* @param int $sourceId An identifier specifying the image type or source requested.
296
* @return string Name of the data source associated with specified id
298
private function _getDataSourceName ($sourceId)
300
$sql = "SELECT name FROM datasources WHERE id=$sourceId";
301
$result = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
302
return $result["name"];
306
* Returns the number of images in the database for a given source and time range
308
* @param datetime $start Query start time
309
* @param datetime $end Query end time
310
* @param int $sourceId The sourceId to query
312
* @return int The number of images in the database within the specified constraints
314
public function getImageCount($start, $end, $sourceId)
316
include_once 'src/Helper/DateTimeConversions.php';
317
$startDate = isoDateToMySQL($start);
318
$endDate = isoDateToMySQL($end);
320
$sql = "SELECT COUNT(*) FROM images WHERE sourceId=$sourceId AND date BETWEEN '$startDate' AND '$endDate'";
322
$result = mysqli_fetch_array($this->_dbConnection->query($sql));
323
return (int) $result[0];
327
* Returns an array containing all images for a given source and time range
329
* @param datetime $start Query start time
330
* @param datetime $end Query end time
331
* @param int $sourceId The sourceId to query
333
* @return int The number of images in the database within the specified constraints
335
public function getImageRange($start, $end, $sourceId)
337
include_once 'src/Helper/DateTimeConversions.php';
338
$startDate = isoDateToMySQL($start);
339
$endDate = isoDateToMySQL($end);
342
$sql = "SELECT * FROM images
343
WHERE sourceId=$sourceId AND date BETWEEN '$startDate' AND '$endDate' ORDER BY date ASC";
345
$result = $this->_dbConnection->query($sql);
347
while ($image = $result->fetch_array(MYSQL_ASSOC)) {
348
array_push($images, $image);
354
* Extract necessary meta-information from an image
356
* @param string $img Location of a JP2 image.
358
* @return array A subset of the information stored in the jp2 header
360
public function extractJP2MetaInfo ($img)
362
include_once "src/Image/JPEG2000/JP2ImageXMLBox.php";
365
$xmlBox = new Image_JPEG2000_JP2ImageXMLBox($img);
367
$dimensions = $xmlBox->getImageDimensions();
368
$center = $xmlBox->getSunCenter();
369
$imageScale = (float) $xmlBox->getImagePlateScale();
370
$dsun = (float) $xmlBox->getDSun();
372
// Normalize image scale
373
$imageScale = $imageScale * ($dsun / HV_CONSTANT_AU);
376
"scale" => $imageScale,
377
"width" => (int) $dimensions[0],
378
"height" => (int) $dimensions[1],
379
"sunCenterX" => (float) $center[0],
380
"sunCenterY" => (float) $center[1]
382
} catch (Exception $e) {
383
throw new Exception(sprintf("Unable to process XML Header for %s: %s", $img, $e->getMessage()));
390
* Takes in a source id and returns the corresponding
391
* observatory, instrument, detector, measurement, and
392
* layeringOrder information.
394
* @param {int} $id Source Id
396
* @return {Array} $result_array Contains values for
397
* "observatory", "instrument", "detector", "measurement",
398
* and "layeringOrder"
400
public function getDatasourceInformationFromSourceId ($id)
404
observatories.name AS observatory,
405
instruments.name AS instrument,
406
detectors.name AS detector,
407
measurements.name AS measurement,
408
datasources.name AS name,
409
datasources.layeringOrder AS layeringOrder
411
LEFT JOIN observatories ON datasources.observatoryId = observatories.id
412
LEFT JOIN instruments ON datasources.instrumentId = instruments.id
413
LEFT JOIN detectors ON datasources.detectorId = detectors.id
414
LEFT JOIN measurements ON datasources.measurementId = measurements.id
416
datasources.id='%s'",
417
mysqli_real_escape_string($this->_dbConnection->link, $id)
420
$result = $this->_dbConnection->query($sql);
421
$result_array = mysqli_fetch_array($result, MYSQL_ASSOC);
423
return $result_array;
427
* Returns the source Id, name, and layering order associated with a data source specified by
428
* it's observatory, instrument, detector and measurement.
430
* @param string $obs Observatory
431
* @param string $inst Instrument
432
* @param string $det Detector
433
* @param string $meas Measurement
435
* @return array Datasource id and layering order
437
public function getDatasourceInformationFromNames($obs, $inst, $det, $meas)
441
datasources.id AS id,
442
datasources.name AS name,
443
datasources.layeringOrder AS layeringOrder
445
LEFT JOIN observatories ON datasources.observatoryId = observatories.id
446
LEFT JOIN instruments ON datasources.instrumentId = instruments.id
447
LEFT JOIN detectors ON datasources.detectorId = detectors.id
448
LEFT JOIN measurements ON datasources.measurementId = measurements.id
450
observatories.name='%s' AND
451
instruments.name='%s' AND
452
detectors.name='%s' AND
453
measurements.name='%s';",
454
mysqli_real_escape_string($this->_dbConnection->link, $obs),
455
mysqli_real_escape_string($this->_dbConnection->link, $inst),
456
mysqli_real_escape_string($this->_dbConnection->link, $det),
457
mysqli_real_escape_string($this->_dbConnection->link, $meas)
459
$result = $this->_dbConnection->query($sql);
460
$result_array = mysqli_fetch_array($result, MYSQL_ASSOC);
462
return $result_array;
466
* Returns the sourceId for a given set of parameters.
468
* @param string $obs Observatory
469
* @param string $inst Instrument
470
* @param string $det Detector
471
* @param string $meas Measurement
473
* @return int The matched sourceId.
475
public function getSourceId ($obs, $inst, $det, $meas)
481
LEFT JOIN observatories ON datasources.observatoryId = observatories.id
482
LEFT JOIN instruments ON datasources.instrumentId = instruments.id
483
LEFT JOIN detectors ON datasources.detectorId = detectors.id
484
LEFT JOIN measurements ON datasources.measurementId = measurements.id
486
observatories.name='%s' AND
487
instruments.name='%s' AND
488
detectors.name='%s' AND
489
measurements.name='%s';",
490
mysqli_real_escape_string($this->_dbConnection->link, $obs),
491
mysqli_real_escape_string($this->_dbConnection->link, $inst),
492
mysqli_real_escape_string($this->_dbConnection->link, $det),
493
mysqli_real_escape_string($this->_dbConnection->link, $meas)
495
$result = $this->_dbConnection->query($sql);
496
$result_array = mysqli_fetch_array($result, MYSQL_ASSOC);
498
return (int) ($result_array["id"]);
502
* Returns the oldest image for a given datasource
504
public function getOldestImage($sourceId)
506
$sql = "SELECT date FROM images WHERE sourceId=$sourceId ORDER BY date ASC LIMIT 1";
507
$result = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
508
return $result['date'];
512
* Returns the newest image for a given datasource
514
public function getNewestImage($sourceId)
516
$sql = "SELECT date FROM images WHERE sourceId=$sourceId ORDER BY date DESC LIMIT 1";
517
$result = mysqli_fetch_array($this->_dbConnection->query($sql), MYSQL_ASSOC);
518
return $result['date'];
522
* Returns a list of datasources sorted by instrument
524
* @return array A list of datasources sorted by instrument
526
public function getDataSourcesByInstrument ()
528
// 2011/05/24: Hiding TRACE for now
529
$result = $this->_dbConnection->query("SELECT * FROM instruments WHERE name != 'TRACE' ORDER BY name");
531
$instruments = array();
533
while($instrument = mysqli_fetch_assoc($result)) {
534
$instruments[$instrument['name']] = array();
535
$sql = sprintf("SELECT * FROM datasources WHERE instrumentId=%d ORDER BY name", $instrument['id']);
536
$datasources = $this->_dbConnection->query($sql);
537
while($ds = mysqli_fetch_assoc($datasources)) {
538
array_push($instruments[$instrument['name']], $ds);
546
* Returns a list of the known data sources
548
* @param bool $verbose If set to true an alternative data structure is returned that includes meta-information
549
* at each level of the tree, and adds units to numeric measurement names
551
* @return array A tree representation of the known data sources
553
public function getDataSources ($verbose)
555
$fields = array("instrument", "detector", "measurement");
558
datasources.name as nickname,
559
datasources.id as id,
560
datasources.enabled as enabled,
561
datasources.layeringOrder as layeringOrder,
562
measurements.units as measurement_units,
563
observatories.name as observatory_name,
564
observatories.description as observatory_description, ";
566
foreach ($fields as $field) {
567
$sql .= sprintf("%ss.name as %s_name, %ss.description as %s_description,", $field, $field, $field, $field);
570
$sql = substr($sql, 0, -1) . " " .
572
LEFT JOIN observatories ON datasources.observatoryId = observatories.id
573
LEFT JOIN instruments ON datasources.instrumentId = instruments.id
574
LEFT JOIN detectors ON datasources.detectorId = detectors.id
575
LEFT JOIN measurements ON datasources.measurementId = measurements.id;";
577
// 2011/06/10 Temporarily hiding STEREO from verbose output (used by
578
// JHelioviewer.) Will remove when JHelioviewer adds support.
580
// 2012/05/26 Same thing with SWAP
582
$sql = substr($sql, 0, -1) . " " . 'WHERE observatories.name NOT IN ("STEREO_A", "STEREO_B", "PROBA2");';
585
// Use UTF-8 for responses
586
$this->_dbConnection->setEncoding('utf8');
588
// Fetch available data-sources
589
$result = $this->_dbConnection->query($sql);
593
while ($row = $result->fetch_array(MYSQL_ASSOC)) {
594
array_push($sources, $row);
597
// Convert results into a more easily traversable tree structure
600
foreach ($sources as $source) {
602
$enabled = (bool) $source["enabled"];
604
// Only include if data is available for the specified source
610
$id = (int) ($source["id"]);
611
$obs = $source["observatory_name"];
612
$inst = $source["instrument_name"];
613
$det = $source["detector_name"];
614
$meas = $source["measurement_name"];
615
$nickname = $source["nickname"];
616
$order = (int) ($source["layeringOrder"]);
619
$oldest = $this->getOldestImage($id);
620
$newest = $this->getNewestImage($id);
625
if (!isset($tree[$obs])) {
626
$tree[$obs] = array();
628
if (!isset($tree[$obs][$inst])) {
629
$tree[$obs][$inst] = array();
631
if (!isset($tree[$obs][$inst][$det])) {
632
$tree[$obs][$inst][$det] = array();
634
$tree[$obs][$inst][$det][$meas] = array(
636
"nickname" => $nickname,
637
"layeringOrder" => $order,
642
// Alternative measurement descriptors
643
if (preg_match("/^\d*$/", $meas)) {
644
// \u205f = \xE2\x81\x9F = MEDIUM MATHEMATICAL SPACE
645
$measurementName = $meas . "\xE2\x81\x9F" . $source["measurement_units"];
647
$measurementName = ucwords(str_replace("-", " ", $meas));
652
if (!isset($tree[$obs])) {
655
"description" => $source["observatory_description"],
656
"children" => array()
659
if (!isset($tree[$obs]["children"][$inst])) {
660
$tree[$obs]["children"][$inst] = array(
662
"description" => $source["instrument_description"],
663
"children" => array()
666
if (!isset($tree[$obs]["children"][$inst]["children"][$det])) {
667
$tree[$obs]["children"][$inst]["children"][$det] = array(
669
"description" => $source["detector_description"],
670
"children" => array()
673
$tree[$obs]["children"][$inst]["children"][$det]["children"][$meas] = array(
674
"name" => $measurementName,
675
"description" => $source["measurement_description"],
676
"nickname" => $nickname,
678
"layeringOrder" => $order,
685
// Set defaults for verbose mode
687
$tree["SDO"]["default"] = true;
688
$tree["SDO"]["children"]["AIA"]["default"] = true;
689
$tree["SDO"]["children"]["AIA"]["children"]["AIA"]["default"] = true;
690
$tree["SDO"]["children"]["AIA"]["children"]["AIA"]["children"]["171"]["default"] = true;
697
* Finds the closest match for a requested image and returns it's location
699
* @param string $date A UTC date string of the form "2003-10-05T00:00:00Z."
700
* @param int $sourceId An identifier specifying the image type or source requested.
702
* @return string Local filepath for the JP2 image.
705
public function getJP2FilePath($date, $sourceId)
707
$img = $this->getImageFromDatabase($date, $sourceId);
708
return $img["filepath"] . "/" . $img["filename"];
712
* Returns the filepath for the image with the specified id
714
* @param int $id Image id
716
* @return string Local filepath for the JP2 image
718
public function getJP2FilePathFromId($id)
720
$sql = "SELECT concat(filepath, '/', filename) FROM images WHERE id=$id";
721
$row = mysqli_fetch_array($this->_dbConnection->query($sql));
722
return array_pop($row);