map: add migration
parent
72a08b917f
commit
1751ad7d80
|
@ -58,6 +58,7 @@ class MapController extends ApiBase
|
|||
|
||||
try {
|
||||
$clusters = $this->timelineQuery->getMapClusters($gridLen, $bounds, $root);
|
||||
|
||||
return new JSONResponse($clusters);
|
||||
} catch (\Exception $e) {
|
||||
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR);
|
||||
|
|
|
@ -44,7 +44,7 @@ trait TimelineQueryMap
|
|||
$count = $query->createFunction('COUNT(m.fileid) AS count');
|
||||
|
||||
$query->select($lat, $lon, $count)
|
||||
->from('memories_map_clusters', 'c')
|
||||
->from('memories_mapclusters', 'c')
|
||||
;
|
||||
|
||||
if ($gridLen > 0.02) {
|
||||
|
@ -58,7 +58,7 @@ trait TimelineQueryMap
|
|||
}
|
||||
|
||||
// JOIN with memories for files from the current user
|
||||
$query->innerJoin('c', 'memories', 'm', $query->expr()->eq('c.id', 'm.map_cluster_id'));
|
||||
$query->innerJoin('c', 'memories', 'm', $query->expr()->eq('c.id', 'm.mapcluster'));
|
||||
|
||||
// JOIN with filecache for existing files
|
||||
$query = $this->joinFilecache($query, $root, true, false);
|
||||
|
@ -96,7 +96,7 @@ trait TimelineQueryMap
|
|||
|
||||
// SELECT all photos with this tag
|
||||
$query->select('f.fileid', 'f.etag')->from('memories', 'm')->where(
|
||||
$query->expr()->eq('m.map_cluster_id', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT))
|
||||
$query->expr()->eq('m.mapcluster', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT))
|
||||
);
|
||||
|
||||
// WHERE these photos are in the user's requested folder recursively
|
||||
|
|
|
@ -15,6 +15,7 @@ use Psr\Log\LoggerInterface;
|
|||
require_once __DIR__.'/../ExifFields.php';
|
||||
|
||||
const DELETE_TABLES = ['memories', 'memories_livephoto', 'memories_places'];
|
||||
const TRUNCATE_TABLES = ['memories_mapclusters'];
|
||||
|
||||
class TimelineWrite
|
||||
{
|
||||
|
@ -82,7 +83,7 @@ class TimelineWrite
|
|||
|
||||
// Check if need to update
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->select('fileid', 'mtime', 'map_cluster_id')
|
||||
$query->select('fileid', 'mtime', 'mapcluster')
|
||||
->from('memories')
|
||||
->where($query->expr()->eq('fileid', $query->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)))
|
||||
;
|
||||
|
@ -163,16 +164,24 @@ class TimelineWrite
|
|||
// Store location data
|
||||
$lat = null;
|
||||
$lon = null;
|
||||
$mapCluster = $prevRow ? (int) $prevRow['map_cluster_id'] : -1;
|
||||
$mapCluster = $prevRow ? (int) $prevRow['mapcluster'] : -1;
|
||||
if (\array_key_exists('GPSLatitude', $exif) && \array_key_exists('GPSLongitude', $exif)) {
|
||||
try {
|
||||
$lat = (float) $exif['GPSLatitude'];
|
||||
$lon = (float) $exif['GPSLongitude'];
|
||||
$mapCluster = $this->getMapCluster($fileId, $mapCluster, $lat, $lon);
|
||||
|
||||
try {
|
||||
$mapCluster = $this->getMapCluster($mapCluster, $lat, $lon);
|
||||
$mapCluster = $mapCluster <= 0 ? null : $mapCluster;
|
||||
} catch (\Error $e) {
|
||||
$logger = \OC::$server->get(LoggerInterface::class);
|
||||
$logger->log(3, 'Error updating map cluster data: '.$e->getMessage(), ['app' => 'memories']);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->updatePlacesData($fileId, $lat, $lon);
|
||||
} catch (\Error $e) {
|
||||
$logger = \OC::$server->get(LoggerInterface::class);
|
||||
$logger->log(3, 'Error updating geo data: '.$e->getMessage(), ['app' => 'memories']);
|
||||
$logger->log(3, 'Error updating places data: '.$e->getMessage(), ['app' => 'memories']);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,7 +200,7 @@ class TimelineWrite
|
|||
'liveid' => $query->createNamedParameter($liveid, IQueryBuilder::PARAM_STR),
|
||||
'lat' => $query->createNamedParameter($lat, IQueryBuilder::PARAM_STR),
|
||||
'lon' => $query->createNamedParameter($lon, IQueryBuilder::PARAM_STR),
|
||||
'map_cluster_id' => $query->createNamedParameter($mapCluster, IQueryBuilder::PARAM_INT),
|
||||
'mapcluster' => $query->createNamedParameter($mapCluster, IQueryBuilder::PARAM_INT),
|
||||
];
|
||||
|
||||
if ($prevRow) {
|
||||
|
@ -241,7 +250,7 @@ class TimelineWrite
|
|||
public function clear()
|
||||
{
|
||||
$p = $this->connection->getDatabasePlatform();
|
||||
foreach (DELETE_TABLES as $table) {
|
||||
foreach (array_merge(DELETE_TABLES, TRUNCATE_TABLES) as $table) {
|
||||
$this->connection->executeStatement($p->getTruncateTableSQL('*PREFIX*'.$table, false));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,27 +7,27 @@ namespace OCA\Memories\Db;
|
|||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IDBConnection;
|
||||
|
||||
const CLUSTER_DEG = 0.0003;
|
||||
|
||||
trait TimelineWriteMap
|
||||
{
|
||||
protected IDBConnection $connection;
|
||||
|
||||
protected function getMapCluster(int $fileId, int $prevCluster, float $lat, float $lon): int
|
||||
protected function getMapCluster(int $prevCluster, float $lat, float $lon): int
|
||||
{
|
||||
// get all clusters within 30 metres
|
||||
// Get all possible clusters within CLUSTER_DEG radius
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->select('id')
|
||||
->from('memories_map_clusters')
|
||||
->andWhere($query->expr()->gte('lat', $query->createNamedParameter($lat - 0.0003, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($query->expr()->lte('lat', $query->createNamedParameter($lat + 0.0003, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($query->expr()->gte('lon', $query->createNamedParameter($lon - 0.0003, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($query->expr()->lte('lon', $query->createNamedParameter($lon + 0.0003, IQueryBuilder::PARAM_STR)))
|
||||
$query->select('id', 'lat', 'lon')
|
||||
->from('memories_mapclusters')
|
||||
->andWhere($query->expr()->gte('lat', $query->createNamedParameter($lat - CLUSTER_DEG, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($query->expr()->lte('lat', $query->createNamedParameter($lat + CLUSTER_DEG, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($query->expr()->gte('lon', $query->createNamedParameter($lon - CLUSTER_DEG, IQueryBuilder::PARAM_STR)))
|
||||
->andWhere($query->expr()->lte('lon', $query->createNamedParameter($lon + CLUSTER_DEG, IQueryBuilder::PARAM_STR)))
|
||||
;
|
||||
|
||||
$result = $query->executeQuery();
|
||||
$rows = $result->fetchAll();
|
||||
$rows = $query->executeQuery()->fetchAll();
|
||||
|
||||
// Find cluster closest to the point
|
||||
$minDist = 999999999;
|
||||
$minDist = PHP_INT_MAX;
|
||||
$minId = -1;
|
||||
foreach ($rows as $r) {
|
||||
$clusterLat = (float) $r['lat'];
|
||||
|
@ -59,10 +59,28 @@ trait TimelineWriteMap
|
|||
return $minId;
|
||||
}
|
||||
|
||||
protected function createMapCluster(float $lat, float $lon): int
|
||||
protected function addToCluster(int $clusterId, float $lat, float $lon): void
|
||||
{
|
||||
if ($clusterId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->update('memories_mapclusters')
|
||||
->set('point_count', $query->createFunction('point_count + 1'))
|
||||
->set('lat_sum', $query->createFunction("lat_sum + {$lat}"))
|
||||
->set('lon_sum', $query->createFunction("lon_sum + {$lon}"))
|
||||
->set('lat', $query->createFunction('lat_sum / point_count'))
|
||||
->set('lon', $query->createFunction('lon_sum / point_count'))
|
||||
->where($query->expr()->eq('id', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT)))
|
||||
;
|
||||
$query->executeStatement();
|
||||
}
|
||||
|
||||
private function createMapCluster(float $lat, float $lon): int
|
||||
{
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->insert('memories_map_clusters')
|
||||
$query->insert('memories_mapclusters')
|
||||
->values([
|
||||
'point_count' => $query->createNamedParameter(1, IQueryBuilder::PARAM_INT),
|
||||
'lat_sum' => $query->createNamedParameter($lat, IQueryBuilder::PARAM_STR),
|
||||
|
@ -76,35 +94,17 @@ trait TimelineWriteMap
|
|||
return (int) $query->getLastInsertId();
|
||||
}
|
||||
|
||||
protected function removeFromCluster(int $clusterId, float $lat, float $lon): void
|
||||
private function removeFromCluster(int $clusterId, float $lat, float $lon): void
|
||||
{
|
||||
if ($clusterId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->update('memories_map_clusters')
|
||||
$query->update('memories_mapclusters')
|
||||
->set('point_count', $query->createFunction('point_count - 1'))
|
||||
->set('lat_sum', $query->createFunction('lat_sum - '.$lat))
|
||||
->set('lon_sum', $query->createFunction('lon_sum - '.$lon))
|
||||
->set('lat', $query->createFunction('lat_sum / point_count'))
|
||||
->set('lon', $query->createFunction('lon_sum / point_count'))
|
||||
->where($query->expr()->eq('id', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT)))
|
||||
;
|
||||
$query->executeStatement();
|
||||
}
|
||||
|
||||
protected function addToCluster(int $clusterId, float $lat, float $lon): void
|
||||
{
|
||||
if ($clusterId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->update('memories_map_clusters')
|
||||
->set('point_count', $query->createFunction('point_count + 1'))
|
||||
->set('lat_sum', $query->createFunction('lat_sum + '.$lat))
|
||||
->set('lon_sum', $query->createFunction('lon_sum + '.$lon))
|
||||
->set('lat_sum', $query->createFunction("lat_sum - {$lat}"))
|
||||
->set('lon_sum', $query->createFunction("lon_sum - {$lon}"))
|
||||
->set('lat', $query->createFunction('lat_sum / point_count'))
|
||||
->set('lon', $query->createFunction('lon_sum / point_count'))
|
||||
->where($query->expr()->eq('id', $query->createNamedParameter($clusterId, IQueryBuilder::PARAM_INT)))
|
||||
|
|
|
@ -48,8 +48,8 @@ class Version401100Date20230208181533 extends SimpleMigrationStep
|
|||
/** @var ISchemaWrapper $schema */
|
||||
$schema = $schemaClosure();
|
||||
|
||||
// Add lat lon to memories
|
||||
$table = $schema->getTable('memories');
|
||||
|
||||
if (!$table->hasColumn('lat')) {
|
||||
$table->addColumn('lat', Types::DECIMAL, [
|
||||
'notnull' => false,
|
||||
|
@ -63,8 +63,44 @@ class Version401100Date20230208181533 extends SimpleMigrationStep
|
|||
'precision' => 9,
|
||||
'scale' => 6,
|
||||
]);
|
||||
|
||||
$table->addIndex(['lat', 'lon'], 'memories_lat_lon_index');
|
||||
|
||||
$table->addColumn('mapcluster', Types::INTEGER, [
|
||||
'notnull' => false,
|
||||
'default' => null,
|
||||
]);
|
||||
$table->addIndex(['mapcluster'], 'memories_mapcluster_index');
|
||||
}
|
||||
|
||||
// Add clusters table
|
||||
if (!$schema->hasTable('memories_mapclusters')) {
|
||||
$table = $schema->createTable('memories_mapclusters');
|
||||
$table->addColumn('id', Types::INTEGER, [
|
||||
'autoincrement' => true,
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('point_count', Types::INTEGER, [
|
||||
'notnull' => true,
|
||||
]);
|
||||
$table->addColumn('lat_sum', Types::FLOAT, [
|
||||
'notnull' => false,
|
||||
'default' => null,
|
||||
]);
|
||||
$table->addColumn('lon_sum', Types::FLOAT, [
|
||||
'notnull' => false,
|
||||
'default' => null,
|
||||
]);
|
||||
$table->addColumn('lat', Types::FLOAT, [
|
||||
'notnull' => false,
|
||||
'default' => null,
|
||||
]);
|
||||
$table->addColumn('lon', Types::FLOAT, [
|
||||
'notnull' => false,
|
||||
'default' => null,
|
||||
]);
|
||||
|
||||
$table->setPrimaryKey(['id']);
|
||||
$table->addIndex(['lat', 'lon'], 'memories_clst_ll_idx');
|
||||
}
|
||||
|
||||
return $schema;
|
||||
|
|
Loading…
Reference in New Issue