geolocation-8.x-3.x-dev/modules/geolocation_geometry/src/Plugin/Field/FieldType/GeolocationGeometryBase.php
modules/geolocation_geometry/src/Plugin/Field/FieldType/GeolocationGeometryBase.php
<?php
namespace Drupal\geolocation_geometry\Plugin\Field\FieldType;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;
use Drupal\Core\TypedData\MapDataDefinition;
/**
* Class Geolocation Geometry Base.
*
* @package Drupal\geolocation_geometry\Plugin\Field\FieldType
*
* @property string $geojson
*/
abstract class GeolocationGeometryBase extends FieldItemBase {
/**
* {@inheritdoc}
*/
public static function schema(FieldStorageDefinitionInterface $field_definition): array {
return [
'columns' => [
'geometry' => [
'description' => 'Stores the geometry',
'type' => 'text',
'mysql_type' => 'geometry',
'pgsql_type' => 'geometry',
'size' => 'big',
'not null' => FALSE,
],
'geojson' => [
'description' => 'Stores the geometry as GeoJSON',
'type' => 'text',
'size' => 'big',
'not null' => TRUE,
],
'data' => [
'description' => 'Serialized array of additional data.',
'type' => 'blob',
'size' => 'big',
'not null' => FALSE,
'serialize' => TRUE,
],
],
];
}
/**
* {@inheritdoc}
*/
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition): array {
$geom_type = explode("_", $field_definition->getType())[2];
$properties['geojson'] = DataDefinition::create('string')
->setLabel(t('GeoJSON'))
->addConstraint(
'GeometryType',
['geometryType' => $geom_type, 'type' => 'GeoJSON']
);
$properties['data'] = MapDataDefinition::create()->setLabel(t('Meta data'));
return $properties;
}
/**
* {@inheritdoc}
*/
public static function mainPropertyName(): string {
return 'geojson';
}
/**
* {@inheritdoc}
*/
public function postSave($update): bool {
parent::postSave($update);
$entity = $this->getEntity();
$entity_storage = \Drupal::entityTypeManager()->getStorage($entity->getEntityTypeId());
if (!is_a($entity_storage, '\Drupal\Core\Entity\Sql\SqlContentEntityStorage')) {
return FALSE;
}
/** @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage $entity_storage */
$table_mapping = $entity_storage->getTableMapping();
$field_storage_definition = $this->getFieldDefinition()->getFieldStorageDefinition();
if ($entity->getEntityType()->isRevisionable()) {
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
// @phpstan-ignore-next-line
$revision_query = \Drupal::database()->update($table_mapping->getDedicatedRevisionTableName($field_storage_definition));
$revision_query->expression($field_storage_definition->getName() . '_geometry', 'ST_GeomFromGeoJSON(' . $field_storage_definition->getName() . '_geojson)');
if (empty($this->values['data'])) {
$revision_query->fields([$field_storage_definition->getName() . '_data' => serialize(NULL)]);
}
$revision_query->condition('entity_id', $entity->id());
$revision_query->condition('revision_id', $entity->getRevisionId());
$revision_query->condition('bundle', $entity->bundle());
$revision_query->condition('delta', $this->getName());
$revision_query->execute();
}
// @phpstan-ignore-next-line
$query = \Drupal::database()->update($table_mapping->getDedicatedDataTableName($field_storage_definition));
$query->expression($field_storage_definition->getName() . '_geometry', 'ST_GeomFromGeoJSON(' . $field_storage_definition->getName() . '_geojson)');
if (empty($this->values['data'])) {
$query->fields([$field_storage_definition->getName() . '_data' => serialize(NULL)]);
}
$query->condition('entity_id', $entity->id());
$query->condition('bundle', $entity->bundle());
$query->condition('delta', $this->getName());
$query->execute();
return FALSE;
}
/**
* {@inheritdoc}
*/
public static function generateSampleValue(FieldDefinitionInterface $field_definition): array {
$coordinates = self::getRandomCoordinates();
$values['geojson'] = '{"type": "Point", "coordinates": [' . $coordinates['longitude'] . ', ' . $coordinates['latitude'] . ']}';
return $values;
}
/**
* Return a random set of latitude/longitude.
*
* @return float[]
* Coordinates.
*/
protected static function getRandomCoordinates(?array $reference_point = NULL, float $range = 5): array {
// @todo Update to Gemeotry!
if ($reference_point) {
return [
'latitude' => rand(
(int) max(-89, ($reference_point['latitude'] - $range)),
(int) min(90, ($reference_point['latitude'] + $range))
) - (rand(0, 999999) / 1000000),
'longitude' => rand(
(int) max(-179, ($reference_point['longitude'] - $range)),
(int) min(180, ($reference_point['longitude'] + $range))
) - (rand(0, 999999) / 1000000),
];
}
return [
'latitude' => rand(-89, 90) - rand(0, 999999) / 1000000,
'longitude' => rand(-179, 180) - rand(0, 999999) / 1000000,
];
}
/**
* Sort by angle from center point.
*
* @param array $coordinate1
* Coordinate.
* @param array $coordinate2
* Coordinate.
* @param array $center_point
* Center Coordinate.
*
* @return int
* Sort.
*/
protected static function sortCoordinatesByAngle(array $coordinate1, array $coordinate2, array $center_point = []): int {
if (empty($center_point)) {
$center_point = ['latitude' => 0, 'longitude' => 0];
}
return atan2($coordinate1['latitude'] - $center_point['latitude'], $coordinate1['longitude'] - $center_point['longitude']) * 180 / M_PI >
atan2($coordinate2['latitude'] - $center_point['latitude'], $coordinate2['longitude'] - $center_point['longitude']) * 180 / M_PI ? 1 : -1;
}
/**
* Get a center latitude,longitude from an array of like geopoints.
*
* For Example:
* $data = array
* (
* 0 = > array(45.849382, 76.322333),
* 1 = > array(45.843543, 75.324143),
* 2 = > array(45.765744, 76.543223),
* 3 = > array(45.784234, 74.542335)
* );
*
* @param array $coordinates
* Coordinates.
*/
protected static function getCenterFromCoordinates(array $coordinates): array {
$x = 0.0;
$y = 0.0;
$z = 0.0;
foreach ($coordinates as $coordinate) {
$lat = $coordinate['latitude'] * pi() / 180;
$lon = $coordinate['longitude'] * pi() / 180;
$a = cos($lat) * cos($lon);
$b = cos($lat) * sin($lon);
$c = sin($lat);
$x += $a;
$y += $b;
$z += $c;
}
$num_coords = count($coordinates);
$x /= $num_coords;
$y /= $num_coords;
$z /= $num_coords;
$lon = atan2($y, $x);
$hyp = sqrt($x * $x + $y * $y);
$lat = atan2($z, $hyp);
return ['latitude' => $lat * 180 / pi(), 'longitude' => $lon * 180 / pi()];
}
/**
* {@inheritdoc}
*/
public function isEmpty(): bool {
return empty($this->get('geojson')->getValue());
}
}
