built-in tilebbox

This commit is contained in:
Stepan Kuzmin 2018-01-30 11:36:40 +03:00
parent 6e68e9838c
commit e41ca87439
3 changed files with 40 additions and 58 deletions

View File

@ -1,37 +0,0 @@
/* https://github.com/mapbox/postgis-vt-util/blob/master/postgis-vt-util.sql */
/******************************************************************************
### TileBBox ###
Given a Web Mercator tile ID as (z, x, y), returns a bounding-box
geometry of the area covered by that tile.
__Parameters:__
- `integer` z - A tile zoom level.
- `integer` x - A tile x-position.
- `integer` y - A tile y-position.
- `integer` srid - SRID of the desired target projection of the bounding
box. Defaults to 3857 (Web Mercator).
__Returns:__ `geometry(polygon)`
******************************************************************************/
create or replace function TileBBox (z int, x int, y int, srid int = 3857)
returns geometry
language plpgsql immutable as
$func$
declare
max numeric := 20037508.34;
res numeric := (max*2)/(2^z);
bbox geometry;
begin
bbox := ST_MakeEnvelope(
-max + (x * res),
max - (y * res),
-max + (x * res) + res,
max - (y * res) - res,
3857
);
if srid = 3857 then
return bbox;
else
return ST_Transform(bbox, srid);
end if;
end;
$func$;

View File

@ -104,9 +104,9 @@ pub fn tile(req: &mut Request, caps: Captures) -> IronResult<Response> {
} }
}; };
let z: &i32 = &caps["z"].parse().unwrap(); let z: &u32 = &caps["z"].parse().unwrap();
let x: &i32 = &caps["x"].parse().unwrap(); let x: &u32 = &caps["x"].parse().unwrap();
let y: &i32 = &caps["y"].parse().unwrap(); let y: &u32 = &caps["y"].parse().unwrap();
let filter = get_filter(req).cloned(); let filter = get_filter(req).cloned();
let condition = match filter { let condition = match filter {

View File

@ -5,44 +5,61 @@ use std::error::Error;
use super::db::PostgresConnection; use super::db::PostgresConnection;
// https://github.com/mapbox/postgis-vt-util/blob/master/src/TileBBox.sql
fn tilebbox(z: u32, x: u32, y: u32) -> String {
let max = 20037508.34;
let res = (max * 2.0) / (2_i32.pow(z) as f64);
let xmin = -max + (x as f64 * res);
let ymin = max - (y as f64 * res);
let xmax = -max + (x as f64 * res) + res;
let ymax = max - (y as f64 * res) - res;
format!("ST_MakeEnvelope({0}, {1}, {2}, {3}, 3857)", xmin, ymin, xmax, ymax)
}
fn transform(geometry: String, srid: u32) -> String {
if srid == 3857 {
geometry
} else {
format!("ST_Transform({0}, 3857)", geometry)
}
}
#[derive(Serialize, Debug)] #[derive(Serialize, Debug)]
pub struct Tileset { pub struct Tileset {
pub id: String, pub id: String,
schema: String, schema: String,
pub table: String, pub table: String,
geometry_column: String, geometry_column: String,
srid: i32, srid: u32,
extent: i32, extent: u32,
buffer: i32, buffer: u32,
clip_geom: bool, clip_geom: bool,
geometry_type: String, geometry_type: String,
properties: HashMap<String, String> properties: HashMap<String, String>
} }
impl Tileset { impl Tileset {
pub fn get_query(&self, condition: Option<String>) -> String { pub fn get_query(&self, z: u32, x: u32, y: u32, condition: Option<String>) -> String {
let keys: Vec<String> = self.properties.keys().map(|key| key.to_string()).collect(); let keys: Vec<String> = self.properties.keys().map(|key| key.to_string()).collect();
let columns = keys.join(","); let columns = keys.join(",");
let transformed_geometry = if self.srid == 3857 {
self.geometry_column.clone()
} else {
format!("ST_Transform({0}, 3857)", self.geometry_column)
};
let query = format!( let query = format!(
"SELECT ST_AsMVT(tile, '{0}.{1}', {4}, 'geom') FROM (\ "SELECT ST_AsMVT(tile, '{0}.{1}', {4}, 'geom') FROM (\
SELECT \ SELECT \
ST_AsMVTGeom({2}, TileBBox($1, $2, $3, 3857), {4}, {5}, {6}) AS geom, {3} \ ST_AsMVTGeom({2}, {3}, {4}, {5}, {6}) AS geom, \
FROM {0}.{1} {7}\ {7} \
FROM {0}.{1} {8}\
) AS tile;", ) AS tile;",
self.schema, self.schema,
self.table, self.table,
transformed_geometry, transform(self.geometry_column.clone(), self.srid),
columns, tilebbox(z, x, y),
self.extent, self.extent,
self.buffer, self.buffer,
self.clip_geom, self.clip_geom,
columns,
condition.unwrap_or("".to_string()) condition.unwrap_or("".to_string())
); );
@ -97,7 +114,7 @@ pub fn get_tilesets(conn: PostgresConnection) -> Result<HashMap<String, Tileset>
schema: schema, schema: schema,
table: table, table: table,
geometry_column: geometry_column, geometry_column: geometry_column,
srid: srid, srid: srid as u32,
extent: default_extent, extent: default_extent,
buffer: default_buffer, buffer: default_buffer,
clip_geom: default_clip_geom, clip_geom: default_clip_geom,
@ -111,8 +128,10 @@ pub fn get_tilesets(conn: PostgresConnection) -> Result<HashMap<String, Tileset>
Ok(tilesets) Ok(tilesets)
} }
pub fn get_tile<'a>(conn: PostgresConnection, tileset: &Tileset, z: &i32, x: &i32, y: &i32, condition: Option<String>) -> Result<Vec<u8>, Box<Error>> { pub fn get_tile<'a>(conn: PostgresConnection, tileset: &Tileset, z: &u32, x: &u32, y: &u32, condition: Option<String>) -> Result<Vec<u8>, Box<Error>> {
let rows = try!(conn.query(&tileset.get_query(condition), &[&z, &x, &y])); let query = tileset.get_query(z.clone(), x.clone(), y.clone(), condition);
let rows = try!(conn.query(&query, &[]));
let tile = rows.get(0).get("st_asmvt"); let tile = rows.get(0).get("st_asmvt");
Ok(tile) Ok(tile)
} }