mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-23 18:03:17 +00:00
Merge pull request #1566 from mdarse/gps-position-fix
GPS positions handling
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2014 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\SearchEngine\Elastic\Indexer\Record\Hydrator;
|
||||
|
||||
use Assert\Assertion;
|
||||
|
||||
class GpsPosition
|
||||
{
|
||||
const LONGITUDE_TAG_NAME = 'Longitude';
|
||||
const LONGITUDE_REF_TAG_NAME = 'LongitudeRef';
|
||||
const LONGITUDE_REF_WEST = 'W';
|
||||
const LONGITUDE_REF_EAST = 'E';
|
||||
const LATITUDE_TAG_NAME = 'Latitude';
|
||||
const LATITUDE_REF_TAG_NAME = 'LatitudeRef';
|
||||
const LATITUDE_REF_NORTH = 'N';
|
||||
const LATITUDE_REF_SOUTH = 'S';
|
||||
|
||||
private $longitude;
|
||||
private $longitude_ref;
|
||||
private $latitude;
|
||||
private $latitude_ref;
|
||||
|
||||
public function set($tag_name, $value)
|
||||
{
|
||||
switch ($tag_name) {
|
||||
case self::LONGITUDE_TAG_NAME:
|
||||
Assertion::numeric($value);
|
||||
$this->longitude = (float) $value;
|
||||
break;
|
||||
|
||||
case self::LATITUDE_TAG_NAME:
|
||||
Assertion::numeric($value);
|
||||
$this->latitude = (float) $value;
|
||||
break;
|
||||
|
||||
case self::LONGITUDE_REF_TAG_NAME:
|
||||
$normalized = strtoupper($value);
|
||||
if ($normalized !== self::LONGITUDE_REF_EAST && $normalized !== self::LONGITUDE_REF_WEST) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid longitude reference "%s" (expecting "%s" or "%s").', $value, self::LONGITUDE_REF_EAST, self::LONGITUDE_REF_WEST));
|
||||
}
|
||||
$this->longitude_ref = $value;
|
||||
break;
|
||||
|
||||
case self::LATITUDE_REF_TAG_NAME:
|
||||
$normalized = strtoupper($value);
|
||||
if ($normalized !== self::LATITUDE_REF_NORTH && $normalized !== self::LATITUDE_REF_SOUTH) {
|
||||
throw new \InvalidArgumentException(sprintf('Invalid latitude reference "%s" (expecting "%s" or "%s").', $value, self::LATITUDE_REF_NORTH, self::LATITUDE_REF_SOUTH));
|
||||
}
|
||||
$this->latitude_ref = $normalized;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Unsupported tag name "%s".', $tag_name));
|
||||
}
|
||||
}
|
||||
|
||||
public static function isSupportedTagName($tag_name)
|
||||
{
|
||||
return in_array($tag_name, [
|
||||
self::LONGITUDE_TAG_NAME,
|
||||
self::LONGITUDE_REF_TAG_NAME,
|
||||
self::LATITUDE_TAG_NAME,
|
||||
self::LATITUDE_REF_TAG_NAME
|
||||
]);
|
||||
}
|
||||
|
||||
public function isComplete()
|
||||
{
|
||||
return $this->longitude !== null
|
||||
&& $this->longitude_ref !== null
|
||||
&& $this->latitude !== null
|
||||
&& $this->latitude_ref !== null;
|
||||
}
|
||||
|
||||
public function getSignedLongitude()
|
||||
{
|
||||
if ($this->longitude === null) {
|
||||
return null;
|
||||
}
|
||||
return $this->longitude * ($this->longitude_ref === self::LONGITUDE_REF_WEST ? -1 : 1);
|
||||
}
|
||||
|
||||
public function getSignedLatitude()
|
||||
{
|
||||
if ($this->latitude === null) {
|
||||
return null;
|
||||
}
|
||||
return $this->latitude * ($this->latitude_ref === self::LATITUDE_REF_SOUTH ? -1 : 1);
|
||||
}
|
||||
}
|
@@ -19,6 +19,7 @@ use Alchemy\Phrasea\Utilities\StringHelper;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Driver\Connection as DriverConnection;
|
||||
use DomainException;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class MetadataHydrator implements HydratorInterface
|
||||
{
|
||||
@@ -26,6 +27,8 @@ class MetadataHydrator implements HydratorInterface
|
||||
private $structure;
|
||||
private $helper;
|
||||
|
||||
private $gps_position_buffer = [];
|
||||
|
||||
public function __construct(DriverConnection $connection, Structure $structure, RecordHelper $helper)
|
||||
{
|
||||
$this->connection = $connection;
|
||||
@@ -93,12 +96,16 @@ SQL;
|
||||
break;
|
||||
|
||||
case 'exif':
|
||||
// EXIF data is single-valued
|
||||
if (GpsPosition::isSupportedTagName($key)) {
|
||||
$this->handleGpsPosition($records, $id, $key, $value);
|
||||
break;
|
||||
}
|
||||
$tag = $this->structure->getMetadataTagByName($key);
|
||||
if ($tag) {
|
||||
$value = $this->sanitizeValue($value, $tag->getType());
|
||||
}
|
||||
$record['exif'][$key] = $value;
|
||||
// EXIF data is single-valued
|
||||
$record['metadata_tags'][$key] = $value;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -106,6 +113,8 @@ SQL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->clearGpsPositionBuffer();
|
||||
}
|
||||
|
||||
private function sanitizeValue($value, $type)
|
||||
@@ -131,4 +140,26 @@ SQL;
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
private function handleGpsPosition(&$records, $id, $tag_name, $value)
|
||||
{
|
||||
// Get position object
|
||||
if (!isset($this->gps_position_buffer[$id])) {
|
||||
$this->gps_position_buffer[$id] = new GpsPosition();
|
||||
}
|
||||
$position = $this->gps_position_buffer[$id];
|
||||
// Push this tag into object
|
||||
$position->set($tag_name, $value);
|
||||
// Try to output complete position
|
||||
if ($position->isComplete()) {
|
||||
$records[$id]['metadata_tags']['Longitude'] = $position->getSignedLongitude();
|
||||
$records[$id]['metadata_tags']['Latitude'] = $position->getSignedLatitude();
|
||||
unset($this->gps_position_buffer[$id]);
|
||||
}
|
||||
}
|
||||
|
||||
private function clearGpsPositionBuffer()
|
||||
{
|
||||
$this->gps_position_buffer = [];
|
||||
}
|
||||
}
|
||||
|
@@ -307,7 +307,7 @@ class RecordIndexer
|
||||
// Thesaurus
|
||||
->add('concept_path', $this->getThesaurusPathMapping())
|
||||
// EXIF
|
||||
->add('exif', $this->getMetadataTagMapping())
|
||||
->add('metadata_tags', $this->getMetadataTagMapping())
|
||||
// Status
|
||||
->add('flags', $this->getFlagsMapping())
|
||||
->add('flags_bitfield', 'integer')->notIndexed()
|
||||
|
@@ -39,7 +39,7 @@ class Tag implements Typed
|
||||
public function getIndexField($raw = false)
|
||||
{
|
||||
return sprintf(
|
||||
'exif.%s%s',
|
||||
'metadata_tags.%s%s',
|
||||
$this->name,
|
||||
$raw && $this->type === Mapping::TYPE_STRING ? '.raw' : ''
|
||||
);
|
||||
|
@@ -125,7 +125,9 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
|
||||
const TC_DATA_MIMETYPE = 'MimeType';
|
||||
const TC_DATA_FILESIZE = 'FileSize';
|
||||
const TC_DATA_LONGITUDE = 'Longitude';
|
||||
const TC_DATA_LONGITUDE_REF = 'LongitudeRef';
|
||||
const TC_DATA_LATITUDE = 'Latitude';
|
||||
const TC_DATA_LATITUDE_REF = 'LatitudeRef';
|
||||
const TC_DATA_FOCALLENGTH = 'FocalLength';
|
||||
const TC_DATA_CAMERAMODEL = 'CameraModel';
|
||||
const TC_DATA_FLASHFIRED = 'FlashFired';
|
||||
@@ -643,6 +645,10 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
|
||||
self::TC_DATA_VIDEOCODEC => 'getVideoCodec',
|
||||
self::TC_DATA_AUDIOCODEC => 'getAudioCodec',
|
||||
self::TC_DATA_ORIENTATION => 'getOrientation',
|
||||
self::TC_DATA_LONGITUDE => 'getLongitude',
|
||||
self::TC_DATA_LONGITUDE_REF => 'getLongitudeRef',
|
||||
self::TC_DATA_LATITUDE => 'getLatitude',
|
||||
self::TC_DATA_LATITUDE_REF => 'getLatitudeRef',
|
||||
];
|
||||
|
||||
foreach ($methods as $tc_name => $method) {
|
||||
@@ -655,8 +661,6 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
|
||||
}
|
||||
}
|
||||
|
||||
$datas[self::TC_DATA_LONGITUDE] = $media->getLongitude();
|
||||
$datas[self::TC_DATA_LATITUDE] = $media->getLatitude();
|
||||
$datas[self::TC_DATA_MIMETYPE] = $media->getFile()->getMimeType();
|
||||
$datas[self::TC_DATA_FILESIZE] = $media->getFile()->getSize();
|
||||
|
||||
|
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Tests\Phrasea\SearchEngine\Indexer;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\Record\Hydrator\GpsPosition;
|
||||
|
||||
/**
|
||||
* @group unit
|
||||
* @group searchengine
|
||||
* @group indexer
|
||||
*/
|
||||
class GpsPositionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
// 48.856578_N_2.351828_E
|
||||
|
||||
public function testIsCompleteWithSingleSet()
|
||||
{
|
||||
$position = new GpsPosition();
|
||||
$position->set('Latitude', 48.856578);
|
||||
$this->assertFalse($position->isComplete());
|
||||
}
|
||||
|
||||
public function testIsCompleteWithAllSet()
|
||||
{
|
||||
$position = new GpsPosition();
|
||||
$position->set('Latitude', 48.856578);
|
||||
$position->set('LatitudeRef', 'N');
|
||||
$position->set('Longitude', 2.351828);
|
||||
$position->set('LongitudeRef', 'E');
|
||||
$this->assertTrue($position->isComplete());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getSupportedTagNames
|
||||
*/
|
||||
public function testSupportedTagNames($tag_name)
|
||||
{
|
||||
$this->assertTrue(GpsPosition::isSupportedTagName($tag_name));
|
||||
}
|
||||
|
||||
public function getSupportedTagNames()
|
||||
{
|
||||
return [
|
||||
['Longitude'],
|
||||
['LongitudeRef'],
|
||||
['Latitude'],
|
||||
['LatitudeRef'],
|
||||
[GpsPosition::LONGITUDE_TAG_NAME],
|
||||
[GpsPosition::LONGITUDE_REF_TAG_NAME],
|
||||
[GpsPosition::LATITUDE_TAG_NAME],
|
||||
[GpsPosition::LATITUDE_REF_TAG_NAME]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getUnsupportedTagNames
|
||||
*/
|
||||
public function testUnsupportedTagNames($tag_name)
|
||||
{
|
||||
$this->assertFalse(GpsPosition::isSupportedTagName($tag_name));
|
||||
}
|
||||
|
||||
public function getUnsupportedTagNames()
|
||||
{
|
||||
return [
|
||||
['foo'],
|
||||
['lOnGiTuDe']
|
||||
];
|
||||
}
|
||||
|
||||
public function testGetSignedLongitude()
|
||||
{
|
||||
$position = new GpsPosition();
|
||||
$position->set('Longitude', 2.351828);
|
||||
$this->assertEquals(2.351828, $position->getSignedLongitude());
|
||||
|
||||
$position = new GpsPosition();
|
||||
$position->set('LongitudeRef', 'E');
|
||||
$this->assertNull($position->getSignedLongitude());
|
||||
|
||||
$position = new GpsPosition();
|
||||
$position->set('Longitude', 2.351828);
|
||||
$position->set('LongitudeRef', 'E');
|
||||
$this->assertEquals(2.351828, $position->getSignedLongitude());
|
||||
|
||||
$position = new GpsPosition();
|
||||
$position->set('Longitude', 2.351828);
|
||||
$position->set('LongitudeRef', 'W');
|
||||
$this->assertEquals(-2.351828, $position->getSignedLongitude());
|
||||
}
|
||||
|
||||
public function testGetSignedLatitude()
|
||||
{
|
||||
$position = new GpsPosition();
|
||||
$position->set('Latitude', 48.856578);
|
||||
$this->assertEquals(48.856578, $position->getSignedLatitude());
|
||||
|
||||
$position = new GpsPosition();
|
||||
$position->set('LatitudeRef', 'N');
|
||||
$this->assertNull($position->getSignedLatitude());
|
||||
|
||||
$position = new GpsPosition();
|
||||
$position->set('Latitude', 48.856578);
|
||||
$position->set('LatitudeRef', 'N');
|
||||
$this->assertEquals(48.856578, $position->getSignedLatitude());
|
||||
|
||||
$position = new GpsPosition();
|
||||
$position->set('Latitude', 48.856578);
|
||||
$position->set('LatitudeRef', 'S');
|
||||
$this->assertEquals(-48.856578, $position->getSignedLatitude());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user