diff --git a/libs/vector_tile/Cargo.toml b/libs/vector_tile/Cargo.toml index 1fc4a15c..cfaead04 100644 --- a/libs/vector_tile/Cargo.toml +++ b/libs/vector_tile/Cargo.toml @@ -12,6 +12,8 @@ log = "0.4" num-traits = "0.2" pointy = "0.3" protobuf = "2.25" +tile-grid = "0.3" + [build-dependencies] protobuf-codegen-pure = "2.25" diff --git a/libs/vector_tile/src/encoding.rs b/libs/vector_tile/src/encoding.rs index 56fbe4e4..7f2d17fb 100644 --- a/libs/vector_tile/src/encoding.rs +++ b/libs/vector_tile/src/encoding.rs @@ -1,7 +1,8 @@ use std::collections::HashMap; use crate::geometry::{ - Geometry, GeometryLineString, GeometryPoint, GeometryPolygon, MultiPoint, Point, + Command, Geometry, GeometryLineString, GeometryPoint, GeometryPolygon, LineTo, MoveTo, + MultiPoint, Point, }; use crate::protos::vector_tile::{ Tile as ProtoTile, Tile_Feature as ProtoFeature, Tile_GeomType as ProtoGeomType, Tile_GeomType, @@ -52,19 +53,13 @@ const CMD_LINE_TO_PARAMETERS: usize = 2; const CMD_CLOSE_PATH_PARAMETERS: usize = 0; trait ZigZag { - /// Encodes a value to zigzag - fn zigzag(self) -> i32; /// Decodes a value from zigzag encoding fn zagzig(self) -> i32; } impl ZigZag for u32 { - fn zigzag(self) -> i32 { - ((self << 1) ^ (self >> 31)) as i32 - } - fn zagzig(self) -> i32 { - ((self >> 1) as i32 ^ (-((self & 1) as i32))) + ((self >> 1) as i32) ^ (-((self & 1) as i32)) } } @@ -84,7 +79,10 @@ impl Decode for Vec { i += 1; for parameter in 0..count { - points.push(Point::new(self[i + parameter].zagzig(), self[i + parameter + 1].zagzig())); + points.push(Point::new( + self[i + parameter].zagzig(), + self[i + parameter + 1].zagzig(), + )); } i += count * CMD_MOVE_TO_PARAMETERS; @@ -95,27 +93,104 @@ impl Decode for Vec { } else if points.len() > 1 { GeometryPoint::MultiPoint(MultiPoint::new(points)) } else { - GeometryPoint::Point(Point::new(0, 0)); // point is at the origin + GeometryPoint::Point(Point::new(0, 0)) // point is at the origin } } } impl Decode for Vec { fn decode(self) -> GeometryLineString { + let mut commands = vec![]; + let mut i = 0; + while i < self.len() - 1 { + let command = self[i] & 0x7; - i += count * match command { - CMD_MOVE_TO => CMD_MOVE_TO_PARAMETERS, - CMD_LINE_TO => CMD_LINE_TO_PARAMETERS, - CMD_CLOSE_PATH => CMD_CLOSE_PATH_PARAMETERS, - _ => 0, - }; + let count = (self[i] >> 3) as usize; + i += 1; + + for parameter in 0..count { + match command { + CMD_MOVE_TO => { + commands.push(Command::MoveTo(MoveTo { + x: self[i + parameter].zagzig(), + y: self[i + parameter + 1].zagzig(), + })); + } + CMD_LINE_TO => { + commands.push(Command::LineTo(LineTo { + x: self[i + parameter].zagzig(), + y: self[i + parameter + 1].zagzig(), + })); + } + CMD_CLOSE_PATH => { + commands.push(Command::Close); + } + _ => {} + } + } + + i += count + * match command { + CMD_MOVE_TO => CMD_MOVE_TO_PARAMETERS, + CMD_LINE_TO => CMD_LINE_TO_PARAMETERS, + CMD_CLOSE_PATH => CMD_CLOSE_PATH_PARAMETERS, + _ => 0, + }; + } + + GeometryLineString { commands } } } impl Decode for Vec { fn decode(self) -> GeometryPolygon { - GeometryPolygon::Unknown + let mut commands = vec![]; + let mut i = 0; + + while i < self.len() { + let command = self[i] & 0x7; + let count = (self[i] >> 3) as usize; + + // parsed command and count => +1 + i += 1; + + match command { + CMD_MOVE_TO => { + for parameter in 0..count { + let x_index = i; + commands.push(Command::MoveTo(MoveTo { + x: self[x_index].zagzig(), + y: self[x_index + 1].zagzig(), + })); + i += CMD_MOVE_TO_PARAMETERS; + } + } + CMD_LINE_TO => { + for parameter in 0..count { + let x_index = i; + commands.push(Command::LineTo(LineTo { + x: self[x_index].zagzig(), + y: self[x_index + 1].zagzig(), + })); + i += CMD_MOVE_TO_PARAMETERS; + } + } + CMD_CLOSE_PATH => { + for _ in 0..count { + commands.push(Command::Close); + i += CMD_CLOSE_PATH_PARAMETERS; + } + } + _ => { + panic!("error") + } + } + + + } + + GeometryPolygon { commands } } } diff --git a/libs/vector_tile/src/geometry.rs b/libs/vector_tile/src/geometry.rs index cc8a72cb..e776df02 100644 --- a/libs/vector_tile/src/geometry.rs +++ b/libs/vector_tile/src/geometry.rs @@ -20,38 +20,35 @@ pub struct Point { y: Number, } +/// Contains relative coordinates to which the cursor is moved #[derive(Debug)] -pub enum GeometryLineString { - LineString(LineString), - MultiLineString(MultiLineString), - Unknown, +pub struct MoveTo { + pub x: Number, + pub y: Number, +} + +/// Contains relative coordinates to which a line is drawn +#[derive(Debug)] +pub struct LineTo { + pub x: Number, + pub y: Number, } #[derive(Debug)] -pub struct MultiLineString { - lines: Vec, +pub enum Command { + MoveTo(MoveTo), + LineTo(LineTo), + Close, } #[derive(Debug)] -pub struct LineString { - points: Vec, +pub struct GeometryLineString { + pub commands: Vec, } #[derive(Debug)] -pub enum GeometryPolygon { - Polygon(Polygon), - MultiLineString(MultiPolygon), - Unknown, -} - -#[derive(Debug)] -pub struct Polygon { - points: Vec, -} - -#[derive(Debug)] -pub struct MultiPolygon { - polygons: Vec, +pub struct GeometryPolygon { + pub commands: Vec, } #[derive(Debug)] @@ -73,27 +70,3 @@ impl MultiPoint { Self { points } } } - -impl LineString { - pub(crate) fn new(points: Vec) -> Self { - Self { points } - } -} - -impl MultiLineString { - pub(crate) fn new(lines: Vec) -> Self { - Self { lines } - } -} - -impl Polygon { - pub(crate) fn new(points: Vec) -> Self { - Self { points } - } -} - -impl MultiPolygon { - pub(crate) fn new(polygons: Vec) -> Self { - Self { polygons } - } -} diff --git a/libs/vector_tile/src/grid.rs b/libs/vector_tile/src/grid.rs new file mode 100644 index 00000000..3e15d353 --- /dev/null +++ b/libs/vector_tile/src/grid.rs @@ -0,0 +1,86 @@ +use tile_grid::{extent_wgs84_to_merc, Extent, Grid, GridIterator, Origin, Unit}; + +fn web_mercator() -> Grid { + Grid::new( + 256, + 256, + Extent { + minx: -20037508.3427892480, + miny: -20037508.3427892480, + maxx: 20037508.3427892480, + maxy: 20037508.3427892480, + }, + 3857, + Unit::Meters, + // for calculation see fn test_resolutions + vec![ + 156543.0339280410, + 78271.5169640205, + 39135.75848201025, + 19567.879241005125, + 9783.939620502562, + 4891.969810251281, + 2445.9849051256406, + 1222.9924525628203, + 611.4962262814101, + 305.7481131407051, + 152.87405657035254, + 76.43702828517627, + 38.218514142588134, + 19.109257071294067, + 9.554628535647034, + 4.777314267823517, + 2.3886571339117584, + 1.1943285669558792, + 0.5971642834779396, + 0.2985821417389698, + 0.1492910708694849, + 0.07464553543474245, + 0.037322767717371225, + ], + Origin::TopLeft, + ) +} + +/// z, x, z +pub fn get_tile_coordinates_bavaria() -> Vec<(u8, u32, u32)> { + let grid = web_mercator(); + let tile_limits = grid.tile_limits( + extent_wgs84_to_merc(&Extent { + minx: 10.0, + miny: 48.0, + maxx: 12.0, + maxy: 50.0, + }), + 0, + ); + + println!("{:?}", grid.tile_extent(0, 0, 0)); + println!("{:?}", grid.tile_extent(33, 21, 6)); + println!("{:?}", grid.tile_extent_xyz(0, 0, 0)); + + let z = 6; + let griditer = GridIterator::new(z, z, tile_limits); + griditer.collect() +} + +pub fn get_tile_coordinates_tutzing() -> Vec<(u8, u32, u32)> { + let grid = web_mercator(); + let tile_limits = grid.tile_limits( + extent_wgs84_to_merc(&Extent { + minx: 11.2772666, + miny: 47.9125117, + maxx: 11.2772666, + maxy: 47.9125117, + }), + 1, + ); + + println!("{:?}", grid.tile_extent(0, 0, 0)); + println!("{:?}", grid.tile_extent(33, 21, 6)); + println!("{:?}", grid.tile_extent_xyz(0, 0, 0)); + + let z = 12; + let griditer = GridIterator::new(z, z, tile_limits); + griditer.collect() +} diff --git a/libs/vector_tile/src/lib.rs b/libs/vector_tile/src/lib.rs index 89a192ac..ccb3260d 100644 --- a/libs/vector_tile/src/lib.rs +++ b/libs/vector_tile/src/lib.rs @@ -1,9 +1,32 @@ +use std::fs::File; +use std::io; +use std::io::{BufReader, Read}; +use std::path::{Path, PathBuf}; + +use protobuf::Message; + +use crate::encoding::Decode; +use crate::protos::vector_tile::Tile as TileProto; +use crate::tile::Tile; -mod protos; mod encoding; +mod protos; #[cfg(test)] mod tests; +pub mod geometry; pub mod tile; -pub mod geometry; \ No newline at end of file +pub mod grid; + +pub fn parse_tile>(path: P) -> io::Result { + let mut f = File::open(path)?; + let mut reader = BufReader::new(f); + return Ok(parse_tile_reader(&mut reader)); +} + +pub fn parse_tile_reader(reader: &mut dyn Read) -> Tile { + let proto_tile = TileProto::parse_from_reader(reader).unwrap(); + return proto_tile.decode(); +} + diff --git a/libs/vector_tile/src/tests.rs b/libs/vector_tile/src/tests.rs index 3af1e620..fe4e42cb 100644 --- a/libs/vector_tile/src/tests.rs +++ b/libs/vector_tile/src/tests.rs @@ -1,16 +1,20 @@ use std::fs::File; use std::io::BufReader; -use crate::encoding::Decode; use protobuf::Message; +use crate::encoding::Decode; +use crate::grid::get_tile_coordinates_bavaria; +use crate::parse_tile; use crate::protos::vector_tile::Tile; #[test] -fn it_works() { - let mut f = File::open("libs/vector_tile/test_data/europe.pbf").expect("no file found"); - //let mut f = File::open("test_data/europe.pbf").expect("no file found"); - let mut reader = BufReader::new(f); - let x = Tile::parse_from_reader(&mut reader).unwrap().decode(); - println!("{:#?}", x); +fn test_parsing_europe_pbf() { + let tile = parse_tile("libs/vector_tile/test_data/europe.pbf"); + //println!("{:?}", tile); +} + +#[test] +fn test_tile_coordinates_bavaria() { + println!("{:?}", get_tile_coordinates_bavaria()); } diff --git a/libs/vector_tile/src/tile.rs b/libs/vector_tile/src/tile.rs index ef36e5a5..9686c45e 100644 --- a/libs/vector_tile/src/tile.rs +++ b/libs/vector_tile/src/tile.rs @@ -52,6 +52,14 @@ impl Feature { pub fn id(&self) -> u64 { self.internal.get_id() } + + + pub fn geometry(&self) -> &Geometry { + &self.geometry + } + pub fn properties(&self) -> &HashMap { + &self.properties + } } impl Layer { @@ -70,10 +78,18 @@ impl Layer { pub fn name(&self) -> &str { self.internal.get_name() } + + pub fn features(&self) -> &Vec { + &self.features + } } impl Tile { pub(crate) fn new(internal: ProtoTile, layers: Vec) -> Self { Tile { internal, layers } } + + pub fn layers(&self) -> &Vec { + &self.layers + } }