コード例 #1
0
ファイル: ActiveQuery.php プロジェクト: sjaakp/yii2-spatial
 /**
  * @param $from - string|array
  *      string: GeoJson representation of POINT
  *      array:  location in the form [ <lng>, <lat> ] (two floats)
  * @param $attribute - attribute name of POINT
  * @param $radius number - search radius in kilometers
  * @return $this - query that returns models that are near to $from
  *
  * Example usages:
  * $here = [4.9, 52.3];     // longitude and latitude of my place
  * $nearestModel = <model>::find()->nearest($here, <attributeName>, 100)->one();    // search radius is 100 km
  * $fiveNearestModels =  <model>::find()->nearest($here, <attributeName>, 100)->limit(5)->all();
  * $dataProvider = new ActiveDataProvider([ 'query' => <model>::find()->nearest($here, <attributeName>, 100) ]);
  *
  *
  * @link http://www.plumislandmedia.net/mysql/haversine-mysql-nearest-loc/
  * @link https://en.wikipedia.org/wiki/Haversine_formula
  */
 public function nearest($from, $attribute, $radius = 100)
 {
     $lenPerDegree = 111.045;
     // km per degree latitude; for miles, use 69.0
     if (is_string($from)) {
         $feat = SpatialHelper::jsonToGeom($from);
         if ($feat && $feat['type'] == 'Point') {
             $from = $feat['coordinates'];
         }
     }
     if (!is_array($from)) {
         return $this;
     }
     $lng = $from[0];
     $lat = $from[1];
     $dLat = $radius / $lenPerDegree;
     $dLng = $dLat / cos(deg2rad($lat));
     /** @var \yii\db\ActiveRecord $modelCls */
     $modelCls = $this->modelClass;
     $subQuery = $this->create($this)->from($modelCls::tableName())->select(['*', '_lng' => "X({$attribute})", '_lat' => "Y({$attribute})"])->having(['between', '_lng', $lng - $dLng, $lng + $dLng])->andHaving(['between', '_lat', $lat - $dLat, $lat + $dLat]);
     $this->from([$subQuery])->select(['*', '_d' => "{$lenPerDegree}*DEGREES(ACOS(COS(RADIANS(:lt))*COS(RADIANS(_lat))*COS(RADIANS(:lg)-RADIANS(_lng))+SIN(RADIANS(:lt))*SIN(RADIANS(_lat))))"])->params([':lg' => $lng, ':lt' => $lat])->having(['<', '_d', $radius])->orderBy(['_d' => SORT_ASC]);
     $this->where = null;
     $this->limit = null;
     $this->offset = null;
     $this->distinct = null;
     $this->groupBy = null;
     $this->join = null;
     $this->union = null;
     return $this;
 }
コード例 #2
0
ファイル: ActiveRecord.php プロジェクト: sjaakp/yii2-spatial
 public function afterFind()
 {
     parent::afterFind();
     $scheme = static::getTableSchema();
     foreach ($scheme->columns as $column) {
         if (static::isSpatial($column)) {
             $field = $column->name;
             $attr = $this->getAttribute($field);
             // get WKT
             if ($attr) {
                 if (YII_DEBUG && preg_match('/[\\x80-\\xff]+/', $attr)) {
                     /* If you get an exception here, it probably means you have overridden find()
                        and did not return sjaakp\spatial\ActiveQuery. */
                     throw new InvalidCallException('Spatial attribute not converted.');
                 }
                 $geom = SpatialHelper::wktToGeom($attr);
                 // Transform geometry FeatureCollection...
                 if ($geom['type'] == 'GeometryCollection') {
                     $feats = [];
                     foreach ($geom['geometries'] as $g) {
                         $feats[] = ['type' => 'Feature', 'geometry' => $g, 'properties' => $this->featureProperties($field, $g)];
                     }
                     $feature = ['type' => 'FeatureCollection', 'features' => $feats];
                 } else {
                     // ... or to Feature
                     $feature = SpatialHelper::geomToFeature($geom, $this->featureProperties($field, $geom));
                 }
                 $this->setAttribute($field, Json::encode($feature));
             }
         }
     }
 }