geohash.class.php,GeoHash

对9个base32进行排序

[wt3mf9qe, wt3mf9qg, wt3mf9qs, wt3mf9qt, wt3mf9qu, wt3mf9qv, wt3mf9r5, wt3mf9rh, wt3mf9rj]

geohash base32图

7372ac749797

image.png

对9个二进制编码进行排序

1110011001000111001101110010011011001101, 1110011001000111001101110010011011001111, 1110011001000111001101110010011011011000, 1110011001000111001101110010011011011001, 1110011001000111001101110010011011011010, 1110011001000111001101110010011011011011, 1110011001000111001101110010011011100101, 1110011001000111001101110010011011110000, 1110011001000111001101110010011011110001

geohash 二进制图

7372ac749797

image.png

总结:geohash是空间z曲线,可以看出值序是从左下角到右上角的总体是有序的。

在固定精度的geohash曲线上

geohash可以保证一个格子一定落在空间Z曲线上某一个位置(在小范围geohash不能对空间坐标进行排序,大范围下看小范围是有序的)

geohash空间Z曲线上某一点可以保证其临近坐标在Z曲线上都是相邻的

距离保留度:

将二维空间对象映射成一维曲线后,两个对象在二维区间上如果是相近的,那么,在一维曲线中也应当是相近的。一个更优的曲线,理应更大程度上在一维曲线中维持对象在二维空间上的距离,或者说,应该有更高的距离保留度。对于查询而言,更高的距离保留度,也往往意味着更高的Caching命中率。

经Geohash编码后,其顺序与Z-Order编码保持一致,因此,也可以将Geohash理解成Z-Order算法的一种编码机制。Geohash编码带来的显著优势是:以字符串字典顺序表达Z-Order顺序,利用字符串的前缀匹配规则,也可快速实现多边形区域的重叠计算,但在编码效率上却并无任何优势,如sfcurve项目中提供的Z2编码算法,性能要远高于Geohash算法。

http://www.nosqlnotes.com/technotes/hbase/hbase-spatial-index/

package geotool;

import ch.hsr.geohash.BoundingBox;

import ch.hsr.geohash.GeoHash;

import org.geotools.data.DefaultTransaction;

import org.geotools.data.Transaction;

import org.geotools.data.collection.ListFeatureCollection;

import org.geotools.data.shapefile.ShapefileDataStore;

import org.geotools.data.shapefile.ShapefileDataStoreFactory;

import org.geotools.data.simple.SimpleFeatureCollection;

import org.geotools.data.simple.SimpleFeatureSource;

import org.geotools.data.simple.SimpleFeatureStore;

import org.geotools.feature.simple.SimpleFeatureBuilder;

import org.geotools.feature.simple.SimpleFeatureTypeBuilder;

import org.geotools.geometry.jts.JTSFactoryFinder;

import org.geotools.referencing.crs.DefaultGeographicCRS;

import org.locationtech.jts.geom.*;

import org.opengis.feature.simple.SimpleFeature;

import org.opengis.feature.simple.SimpleFeatureType;

import java.io.File;

import java.io.IOException;

import java.io.Serializable;

import java.net.MalformedURLException;

import java.util.*;

import java.util.stream.Collectors;

/**

* 类描述

* @since 2019/10/9 9:47

*/

public class GeoHashEx {

public static void main(String[] args) throws IOException {

double lat = 30.549608;

double lon = 114.376971;

// Geohash编码字符的长度(最大为12)

int precision = 8;

GeoHash geoHash = GeoHash.withCharacterPrecision(lat, lon, precision);

// 使用给定的经纬度坐标生成的二进制编码

String binaryCode = geoHash.toBinaryString();

System.out.println("经纬度坐标: (" + lat + ", " + lon + ")");

System.out.println("二进制编码:" + binaryCode);

// 使用给定的经纬度坐标生成的Geohash字符编码

String hashCode = geoHash.toBase32();

System.out.println("Geohash编码:" + hashCode);

// 从二进制的编码中分离出经度和纬度分别对应的二进制编码

char[] binaryCodes = binaryCode.toCharArray();

List latCodes = new ArrayList();

List lonCodes = new ArrayList();

for (int i = 0; i < binaryCodes.length; i++) {

if (i % 2 == 0) {

lonCodes.add(binaryCodes[i]);

} else {

latCodes.add(binaryCodes[i]);

}

}

// 纬度对应的二进制编码

StringBuilder latCode = new StringBuilder();

// 经度对应的二进制编码

StringBuilder lonCode = new StringBuilder();

for (Character ch : latCodes) {

latCode.append(ch);

}

for (Character ch : lonCodes) {

lonCode.append(ch);

}

System.out.println("纬度二进制编码:" + latCode.toString());

System.out.println("经度二进制编码:" + lonCode.toString());

GeoHash[] adjacent = geoHash.getAdjacent();

List collect = Arrays.stream(adjacent).collect(Collectors.toList());

collect.add(geoHash);

GeometryFactory factory = new GeometryFactory();

Map map = new HashMap<>();

for (GeoHash hash : collect) {

BoundingBox boundingBox = hash.getBoundingBox();

Polygon polygon = factory.createPolygon(new Coordinate[]{

new Coordinate(boundingBox.getMaxLon(), boundingBox.getMaxLat()),

new Coordinate(boundingBox.getMaxLon(), boundingBox.getMinLat()),

new Coordinate(boundingBox.getMinLon(), boundingBox.getMinLat()),

new Coordinate(boundingBox.getMinLon(), boundingBox.getMaxLat()),

new Coordinate(boundingBox.getMaxLon(), boundingBox.getMaxLat()),

});

map.put(hash.toBase32(), polygon);

}

Map sortMap = new TreeMap<>(Comparator.naturalOrder());

sortMap.putAll(map);

List> featureList = new ArrayList<>();

for (Map.Entry entry : sortMap.entrySet()) {

String key = entry.getKey();

String binaryString = GeoHash.fromGeohashString(key).toBinaryString();

Map map1 = new HashMap<>();

map1.put("the_geom", entry.getValue());

map1.put("base32", key);

map1.put("binary", binaryString);

featureList.add(map1);

}

Map> fields = new HashMap<>();

fields.put("the_geom", Polygon.class);

fields.put("base32", String.class);

fields.put("binary", String.class);

GeoUtils.createShpefile(featureList, fields, "F:/pop2pop/b.shp");

}

}

golang

package main

import (

"fmt"

"github.com/jonas-p/go-shp"

"github.com/mmcloughlin/geohash"

"github.com/twpayne/go-geom"

"log"

"strconv"

)

func main() {

lat := 30.549608

lon := 114.376971

hash_base32 := geohash.EncodeWithPrecision(lat, lon, 8)

fmt.Println(hash_base32)

neighbors := geohash.Neighbors(hash_base32)

hashs := append(neighbors, hash_base32)

geomMap := make(map[string]*geom.Polygon, 9)

for _, hash := range hashs {

box := geohash.BoundingBox(hash)

polygon, _ := geom.NewPolygon(geom.XY).SetCoords([][]geom.Coord{

{

{box.MaxLng, box.MaxLat},

{box.MaxLng, box.MinLat},

{box.MinLng, box.MinLat},

{box.MinLng, box.MaxLat},

{box.MaxLng, box.MaxLat},

}})

geomMap[hash] = polygon

}

polygonMap := map[string]*shp.PolyLine{}

for key, multiPlygon := range geomMap {

coordsMultiPolygon := multiPlygon.Coords()

points := make([][]shp.Point, len(coordsMultiPolygon), len(coordsMultiPolygon))

for index, coordsPolygon := range coordsMultiPolygon {

points2 := make([]shp.Point, len(coordsPolygon), len(coordsPolygon))

for j, coord := range coordsPolygon {

x := coord.X()

y := coord.Y()

point := shp.Point{x, y}

points2[j] = point

}

points[index]=points2

}

polygonTemp := shp.NewPolyLine(points)

polygonMap[key] = polygonTemp

}

// points to write

fields := []shp.Field{

// String attribute field with length 25

shp.StringField("base_32", 25),

//shp.StringField("binary", 50),

}

// create and open a shapefile for writing points

shape, err := shp.Create("F:/pop2pop/polygons.shp", shp.POLYGON)

if err != nil {

log.Fatal(err)

}

defer shape.Close()

// setup fields for attributes

shape.SetFields(fields)

// write points and attributes

cursor := 0

for key, polygon := range polygonMap {

shape.Write(polygon)

// write attribute for object n for field 0 (NAME)

//toInt, _ := geohash.ConvertStringToInt(key)

shape.WriteAttribute(cursor, 0, key)

//shape.WriteAttribute(cursor, 1, toInt)

cursor++;

}

points2 := []shp.Point{

shp.Point{10.0, 10.0},

shp.Point{10.0, 15.0},

shp.Point{15.0, 15.0},

shp.Point{15.0, 10.0},

}

// fields to write

fields2 := []shp.Field{

// String attribute field with length 25

shp.StringField("NAME", 25),

}

// create and open a shapefile for writing points

shape2, err := shp.Create("F:/pop2pop/points.shp", shp.POINT)

if err != nil { log.Fatal(err) }

defer shape2.Close()

// setup fields for attributes

shape2.SetFields(fields2)

// write points and attributes

for n, point := range points2 {

shape2.Write(&point)

// write attribute for object n for field 0 (NAME)

shape2.WriteAttribute(n, 0, "Point " + strconv.Itoa(n + 1))

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值