public function test()
 {
     $this->initContext();
     $this->assertEquals(false, RestoGeometryUtil::isValidGeoJSONFeature(null));
     $this->assertEquals(false, RestoGeometryUtil::isValidGeoJSONFeature(array('type' => 'toto')));
     $this->assertEquals(false, RestoGeometryUtil::isValidGeoJSONFeature(array('type' => 'Feature', 'geometry' => 'toto')));
     $this->assertEquals(false, RestoGeometryUtil::isValidGeoJSONFeature(array('type' => 'Feature', 'geometry' => array())));
     $this->assertEquals(false, RestoGeometryUtil::isValidGeoJSONFeature(array('type' => 'Feature', 'geometry' => array(), 'properties' => 'toto')));
     $this->assertEquals(true, RestoGeometryUtil::isValidGeoJSONFeature(array('type' => 'Feature', 'geometry' => array(), 'properties' => array())));
     $this->assertEquals(null, RestoGeometryUtil::geoJSONGeometryToWKT(array('type' => 'toto', 'coordinates' => array())));
     $this->assertEquals('POINT()', RestoGeometryUtil::geoJSONGeometryToWKT(array('type' => 'POINT', 'coordinates' => array())));
     $this->assertEquals('MULTIPOINT()', RestoGeometryUtil::geoJSONGeometryToWKT(array('type' => 'MULTIPOINT', 'coordinates' => array())));
     $this->assertEquals('LINESTRING()', RestoGeometryUtil::geoJSONGeometryToWKT(array('type' => 'LINESTRING', 'coordinates' => array())));
     $this->assertEquals('MULTILINESTRING()', RestoGeometryUtil::geoJSONGeometryToWKT(array('type' => 'MULTILINESTRING', 'coordinates' => array())));
     $this->assertEquals('POLYGON()', RestoGeometryUtil::geoJSONGeometryToWKT(array('type' => 'POLYGON', 'coordinates' => array())));
     $this->assertEquals('MULTIPOLYGON()', RestoGeometryUtil::geoJSONGeometryToWKT(array('type' => 'MULTIPOLYGON', 'coordinates' => array())));
     $this->assertEquals(8.863358410694E-5, RestoGeometryUtil::radiusInDegrees(10, 10));
     $this->assertEquals(array(8.9831528424457E-5, 0.00017966305685804), RestoGeometryUtil::inverseMercator(array(10, 20)));
     $this->assertEquals(null, RestoGeometryUtil::inverseMercator(array(10)));
     $this->assertEquals(null, RestoGeometryUtil::inverseMercator('toto'));
     $this->assertEquals(null, RestoGeometryUtil::forwardMercator('toto'));
     $this->assertEquals(null, RestoGeometryUtil::forwardMercator(array(90, -90)));
     $this->assertEquals(null, RestoGeometryUtil::forwardMercator(array(90, 90)));
     $this->assertEquals(null, RestoGeometryUtil::bboxToMercator(null));
     $this->assertEquals('1113194.9077778,1118889.9747022,1113194.9077778,1118889.9747022', RestoGeometryUtil::bboxToMercator('10,10,10,10'));
 }
Example #2
0
 /**
 * Create JSON feature from new resource xml string
 *
 * <product>
  <title>S1A_IW_OCN__2SDV_20150727T044706_20150727T044731_006992_0097D1_F6DA</title>
  <resourceSize>6317404</resourceSize>
  <startTime>2015-07-27T04:47:06.611</startTime>
  <stopTime>2015-07-27T04:47:31.061</stopTime>
  <productType>OCN</productType>
  <missionId>S1A</missionId>
  <processingLevel>1</processingLevel>
  <mode>IW</mode>
  <absoluteOrbitNumber>6992</absoluteOrbitNumber>
  <orbitDirection>ASCENDING</orbitDirection>
  <s2takeid>38865</s2takeid>
  <cloudcover>0.0</cloudcover>
  <instrument>Multi-Spectral Instrument</instrument>
  <footprint>POLYGON ((-161.306549 21.163258,-158.915909 21.585093,-158.623169 20.077986,-160.989746 19.652864,-161.306549 21.163258))</footprint>
  </product>
 *
 * @param {DOMDocument} $dom : $dom DOMDocument
 */
 private function parseNew($dom)
 {
     /*
      * Retrieves orbit direction
      */
     $orbitDirection = strtolower($dom->getElementsByTagName('orbitDirection')->item(0)->nodeValue);
     $polygon = RestoGeometryUtil::WKTPolygonToArray($dom->getElementsByTagName('footprint')->item(0)->nodeValue);
     /*
      * Initialize feature
      */
     $feature = array('type' => 'Feature', 'geometry' => array('type' => 'Polygon', 'coordinates' => array($polygon)), 'properties' => array('productIdentifier' => $dom->getElementsByTagName('title')->item(0)->nodeValue, 'title' => $dom->getElementsByTagName('title')->item(0)->nodeValue, 'resourceSize' => $dom->getElementsByTagName('resourceSize')->item(0)->nodeValue, 'authority' => 'ESA', 'startDate' => $dom->getElementsByTagName('startTime')->item(0)->nodeValue, 'completionDate' => $dom->getElementsByTagName('stopTime')->item(0)->nodeValue, 'productType' => $dom->getElementsByTagName('productType')->item(0)->nodeValue, 'processingLevel' => $dom->getElementsByTagName('processingLevel')->item(0)->nodeValue, 'platform' => $dom->getElementsByTagName('missionId')->item(0)->nodeValue, 'sensorMode' => $dom->getElementsByTagName('mode')->item(0)->nodeValue, 'orbitNumber' => $dom->getElementsByTagName('absoluteOrbitNumber')->item(0)->nodeValue, 'orbitDirection' => $orbitDirection, 'instrument' => $dom->getElementsByTagName('instrument')->item(0)->nodeValue, 'quicklook' => $this->getLocation($dom), 's2TakeId' => $dom->getElementsByTagName('s2takeid')->item(0)->nodeValue, 'cloudCover' => $dom->getElementsByTagName('cloudCover')->item(0)->nodeValue));
     return $feature;
 }
Example #3
0
 /**
  * Generic code to transform input coordinates array to WKT string
  * 
  * @param array $coordinates
  * @param function $functionName
  * @return type
  */
 private static function coordinatesToString($coordinates, $functionName = null)
 {
     $output = array();
     for ($i = 0, $l = count($coordinates); $i < $l; $i++) {
         switch ($functionName) {
             case 'toPoint':
                 $output[] = RestoGeometryUtil::toPoint($coordinates[$i]);
                 break;
             case 'toLineString':
                 $output[] = RestoGeometryUtil::toLineString($coordinates[$i]);
                 break;
             case 'toPolygon':
                 $output[] = RestoGeometryUtil::toPolygon($coordinates[$i]);
                 break;
             default:
                 $output[] = join(' ', $coordinates[$i]);
         }
     }
     return '(' . join(',', $output) . ')';
 }
Example #4
0
 /**
 * Create JSON feature from new resource xml string
 *
 * <product>
  <title>S1A_IW_OCN__2SDV_20150727T044706_20150727T044731_006992_0097D1_F6DA</title>
  <resourceSize>6317404</resourceSize>
  <startTime>2015-07-27T04:47:06.611</startTime>
  <stopTime>2015-07-27T04:47:31.061</stopTime>
  <productType>OCN</productType>
  <missionId>S1A</missionId>
  <processingLevel>2</processingLevel>
  <mode>IW</mode>
  <absoluteOrbitNumber>6992</absoluteOrbitNumber>
  <orbitDirection>ASCENDING</orbitDirection>
  <swath>IW</swath>
  <polarisation>VV VH</polarisation>
  <missiontakeid>38865</missiontakeid>
  <instrument>Multi-Spectral Instrument</instrument>
  <footprint>POLYGON ((-161.306549 21.163258,-158.915909 21.585093,-158.623169 20.077986,-160.989746 19.652864,-161.306549 21.163258))</footprint>
  </product>
 *
 * @param {DOMDocument} $dom : $dom DOMDocument
 */
 private function parseNew($dom)
 {
     /*
      * Retreives orbit direction
      */
     $orbitDirection = strtolower($dom->getElementsByTagName('orbitDirection')->item(0)->nodeValue);
     /*
      * Performs an inversion of the specified Sentinel-1 quicklooks footprint (inside the ZIP files, i.e SAFE product).
      * The datahub systematically performs an inversion of the Sentinel-1 quicklooks taking as input the quicklook images (.png) inside
      * the ZIP files (i.e. as produced by the S1 ground segment).
      */
     $polygon = array($this->reorderSafeFootprintToDhus(RestoGeometryUtil::WKTPolygonToArray($dom->getElementsByTagName('footprint')->item(0)->nodeValue), $orbitDirection));
     /*
      * Initialize feature
      */
     $feature = array('type' => 'Feature', 'geometry' => array('type' => 'Polygon', 'coordinates' => $polygon), 'properties' => array('productIdentifier' => $dom->getElementsByTagName('title')->item(0)->nodeValue, 'title' => $dom->getElementsByTagName('title')->item(0)->nodeValue, 'resourceSize' => $dom->getElementsByTagName('resourceSize')->item(0)->nodeValue, 'authority' => 'ESA', 'startDate' => $dom->getElementsByTagName('startTime')->item(0)->nodeValue, 'completionDate' => $dom->getElementsByTagName('stopTime')->item(0)->nodeValue, 'productType' => $dom->getElementsByTagName('productType')->item(0)->nodeValue, 'processingLevel' => $dom->getElementsByTagName('processingLevel')->item(0)->nodeValue, 'platform' => $dom->getElementsByTagName('missionId')->item(0)->nodeValue, 'sensorMode' => $dom->getElementsByTagName('mode')->item(0)->nodeValue, 'orbitNumber' => $dom->getElementsByTagName('absoluteOrbitNumber')->item(0)->nodeValue, 'orbitDirection' => $orbitDirection, 'swath' => $dom->getElementsByTagName('swath')->item(0)->nodeValue, 'polarisation' => $dom->getElementsByTagName('polarisation')->item(0)->nodeValue, 'missionTakeId' => $dom->getElementsByTagName('missiontakeid')->item(0)->nodeValue, 'instrument' => $dom->getElementsByTagName('instrument')->item(0)->nodeValue, 'quicklook' => $this->getLocation($dom), 'cloudCover' => 0));
     return $feature;
 }
Example #5
0
 /**
  *
  * PostgreSQL output columns are treated as string
  * thus they need to be converted to their true type
  * 
  * @param Array $rawFeatureArray
  * @return array
  */
 private function correctTypes($rawFeatureArray)
 {
     $corrected = array();
     foreach ($rawFeatureArray as $key => $value) {
         switch ($key) {
             case 'bbox4326':
                 $corrected[$key] = str_replace(' ', ',', substr(substr($rawFeatureArray[$key], 0, strlen($rawFeatureArray[$key]) - 1), 4));
                 $corrected['bbox3857'] = RestoGeometryUtil::bboxToMercator($rawFeatureArray[$key]);
                 break;
             case 'keywords':
                 $corrected[$key] = $this->correctKeywords(json_decode($value, true), $this->collections[$rawFeatureArray['collection']]);
                 break;
             case 'licenseId':
                 $corrected['license'] = isset($this->licenses[$rawFeatureArray['licenseId']]) ? $this->licenses[$rawFeatureArray['licenseId']] : null;
                 break;
             default:
                 $corrected[$key] = $this->castExplicit($key, $value, $this->collections[$rawFeatureArray['collection']]);
         }
     }
     if (!isset($corrected['license'])) {
         $corrected['license'] = $this->collections[$rawFeatureArray['collection']]->license->toArray();
     }
     return $corrected;
 }
Example #6
0
 /**
  * Store feature within {collection}.features table following the class model
  * 
  * @param array $data : array (MUST BE GeoJSON in abstract Model)
  * @param RestoCollection $collection
  * 
  */
 public function storeFeature($data, $collection)
 {
     /*
      * Assume input file or stream is a JSON Feature
      */
     if (!RestoGeometryUtil::isValidGeoJSONFeature($data)) {
         RestoLogUtil::httpError(500, 'Invalid feature description');
     }
     /*
      * Remap properties between RESTo model and input
      * GeoJSON Feature file 
      */
     $properties = $this->mapInputProperties($data);
     /*
      * Add collection to $properties to initialize facet counts on collection
      */
     $properties['collection'] = isset($properties['collection']) ? $properties['collection'] : $collection->name;
     /*
      * Compute unique identifier
      */
     if (!isset($data['id']) || !RestoUtil::isValidUUID($data['id'])) {
         $featureIdentifier = $collection->toFeatureId(isset($properties['productIdentifier']) ? $properties['productIdentifier'] : md5(microtime() . rand()));
     } else {
         $featureIdentifier = $data['id'];
     }
     /*
      * First check if feature is already in database
      * (do this before getKeywords to avoid iTag process)
      */
     if ($collection->context->dbDriver->check(RestoDatabaseDriver::FEATURE, array('featureIdentifier' => $featureIdentifier))) {
         RestoLogUtil::httpError(500, 'Feature ' . $featureIdentifier . ' already in database');
     }
     /*
      * Tag module
      */
     $keywords = array();
     if (isset($collection->context->modules['Tag'])) {
         $tagger = RestoUtil::instantiate($collection->context->modules['Tag']['className'], array($collection->context, $collection->user));
         $keywords = $tagger->getKeywords($properties, $data['geometry']);
     }
     /*
      * Store feature
      */
     $collection->context->dbDriver->store(RestoDatabaseDriver::FEATURE, array('collection' => $collection, 'featureArray' => array('type' => 'Feature', 'id' => $featureIdentifier, 'geometry' => $data['geometry'], 'properties' => array_merge($properties, array('keywords' => $keywords)))));
     return new RestoFeature($collection->context, $collection->user, array('featureIdentifier' => $featureIdentifier));
 }
Example #7
0
 /**
  * Return a RESTo keywords array from an iTag Hierarchical feature
  * 
  * @param array $properties
  * @param array $geometry (GeoJSON)
  */
 private function keywordsFromITag($properties, $geometry)
 {
     /*
      * Initialize keywords array from faceted properties
      */
     $keywords = array();
     /* 
      * Compute keywords from iTag
      */
     if (isset($this->options['iTag'])) {
         $iTag = new iTag(array('dbh' => $this->getDatabaseHandler(isset($this->options['iTag']['database']) ? $this->options['iTag']['database'] : null)));
         $metadata = array('footprint' => RestoGeometryUtil::geoJSONGeometryToWKT($geometry), 'timestamp' => isset($properties['startDate']) ? $properties['startDate'] : null);
         $iTagFeature = $iTag->tag($metadata, isset($this->options['iTag']['taggers']) ? $this->options['iTag']['taggers'] : array());
     }
     if (!isset($iTagFeature) || !isset($iTagFeature['content'])) {
         return $keywords;
     }
     /*
      * Continents, countries, regions and states
      */
     if (isset($iTagFeature['content']['political'])) {
         $keywords = $this->getPoliticalKeywords($iTagFeature['content']['political']);
     }
     /*
      * Physical data
      */
     if (isset($iTagFeature['content']['physical'])) {
         $keywords = array_merge($keywords, $this->getPhysicalKeywords($iTagFeature['content']['physical']));
     }
     /*
      * Landuse and landuse details
      */
     if (isset($iTagFeature['content']['landCover'])) {
         $keywords = array_merge($keywords, $this->getLandCoverKeywords($iTagFeature['content']['landCover']));
     }
     /*
      * Population
      */
     if (isset($iTagFeature['content']['population'])) {
         $keywords = array_merge($keywords, $this->getPopulationKeywords($iTagFeature['content']['population']));
     }
     /*
      * Keywords
      */
     if (isset($iTagFeature['content']['keywords'])) {
         $keywords = array_merge($keywords, $this->getAlwaysKeywords($iTagFeature['content']['keywords']));
     }
     return $keywords;
 }
Example #8
0
 /**
  * Prepare SQL query for spatial operation ST_Distance (Input bbox or polygon)
  * 
  * @param RestoModel $model
  * @param string $filterName
  * @param array $requestParams
  * @param boolean $exclusion
  * @return type
  */
 private function prepareFilterQuery_distance($model, $filterName, $requestParams, $exclusion)
 {
     /*
      * WARNING ! Quick benchmark show that st_distance is 100x slower than st_intersects
      * TODO - check if st_distance performance can be improved.
      */
     $use_distance = false;
     /*
      * geo:lon and geo:lat have preseance to geo:name
      * (avoid double call to Gazetteer)
      */
     if (isset($requestParams['geo:lon']) && isset($requestParams['geo:lat'])) {
         $radius = RestoGeometryUtil::radiusInDegrees(isset($requestParams['geo:radius']) ? floatval($requestParams['geo:radius']) : 10000, $requestParams['geo:lat']);
         if ($use_distance) {
             return 'ST_distance(' . $model->getDbKey($model->searchFilters[$filterName]['key']) . ', ST_GeomFromText(\'' . pg_escape_string('POINT(' . $requestParams['geo:lon'] . ' ' . ($lat = $requestParams['geo:lat'] . ')')) . '\', 4326)) < ' . $radius;
         } else {
             $lonmin = $requestParams['geo:lon'] - $radius;
             $latmin = $requestParams['geo:lat'] - $radius;
             $lonmax = $requestParams['geo:lon'] + $radius;
             $latmax = $requestParams['geo:lat'] + $radius;
             return ($exclusion ? 'NOT ' : '') . 'ST_intersects(' . $model->getDbKey($model->searchFilters[$filterName]['key']) . ", ST_GeomFromText('" . pg_escape_string('POLYGON((' . $lonmin . ' ' . $latmin . ',' . $lonmin . ' ' . $latmax . ',' . $lonmax . ' ' . $latmax . ',' . $lonmax . ' ' . $latmin . ',' . $lonmin . ' ' . $latmin . '))') . "', 4326))";
         }
     }
 }
Example #9
0
 /**
  * Convert feature array to database column/value pairs
  * 
  * @param RestoCollection $collection
  * @param array $featureArray
  * @throws Exception
  */
 private function getColumnsAndValues($collection, $featureArray)
 {
     /*
      * Initialize columns array
      */
     $wkt = RestoGeometryUtil::geoJSONGeometryToWKT($featureArray['geometry']);
     $extent = RestoGeometryUtil::getExtent($wkt);
     /*
      * Compute "in house centroid" to avoid -180/180 date line issue
      */
     $factor = 1;
     if (abs($extent[2] - $extent[0]) >= 180) {
         $factor = -1;
     }
     $columns = array_merge(array($collection->model->getDbKey('identifier') => '\'' . $featureArray['id'] . '\'', $collection->model->getDbKey('collection') => '\'' . $collection->name . '\'', $collection->model->getDbKey('geometry') => 'ST_GeomFromText(\'' . $wkt . '\', 4326)', '_geometry' => 'ST_SplitDateLine(ST_GeomFromText(\'' . $wkt . '\', 4326))', $collection->model->getDbKey('centroid') => 'ST_GeomFromText(\'POINT(' . ($extent[2] + $extent[0] * $factor) / 2.0 . ' ' . ($extent[3] + $extent[1]) / 2.0 . ')\', 4326)', 'updated' => 'now()', 'published' => 'now()'), $this->propertiesToColumns($collection, $featureArray['properties']));
     return $columns;
 }