Fix parsing and add grid handling

This commit is contained in:
Maximilian Ammann 2021-12-01 17:55:26 +01:00
parent 742d510ed4
commit a788c14d7a
7 changed files with 251 additions and 72 deletions

View File

@ -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"

View File

@ -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<GeometryPoint> for Vec<u32> {
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<GeometryPoint> for Vec<u32> {
} 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<GeometryLineString> for Vec<u32> {
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<GeometryPolygon> for Vec<u32> {
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 }
}
}

View File

@ -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<LineString>,
pub enum Command {
MoveTo(MoveTo),
LineTo(LineTo),
Close,
}
#[derive(Debug)]
pub struct LineString {
points: Vec<Point>,
pub struct GeometryLineString {
pub commands: Vec<Command>,
}
#[derive(Debug)]
pub enum GeometryPolygon {
Polygon(Polygon),
MultiLineString(MultiPolygon),
Unknown,
}
#[derive(Debug)]
pub struct Polygon {
points: Vec<Point>,
}
#[derive(Debug)]
pub struct MultiPolygon {
polygons: Vec<Polygon>,
pub struct GeometryPolygon {
pub commands: Vec<Command>,
}
#[derive(Debug)]
@ -73,27 +70,3 @@ impl MultiPoint {
Self { points }
}
}
impl LineString {
pub(crate) fn new(points: Vec<Point>) -> Self {
Self { points }
}
}
impl MultiLineString {
pub(crate) fn new(lines: Vec<LineString>) -> Self {
Self { lines }
}
}
impl Polygon {
pub(crate) fn new(points: Vec<Point>) -> Self {
Self { points }
}
}
impl MultiPolygon {
pub(crate) fn new(polygons: Vec<Polygon>) -> Self {
Self { polygons }
}
}

View File

@ -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()
}

View File

@ -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;
pub mod grid;
pub fn parse_tile<P: AsRef<Path>>(path: P) -> io::Result<Tile> {
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();
}

View File

@ -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());
}

View File

@ -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<String, PropertyValue> {
&self.properties
}
}
impl Layer {
@ -70,10 +78,18 @@ impl Layer {
pub fn name(&self) -> &str {
self.internal.get_name()
}
pub fn features(&self) -> &Vec<Feature> {
&self.features
}
}
impl Tile {
pub(crate) fn new(internal: ProtoTile, layers: Vec<Layer>) -> Self {
Tile { internal, layers }
}
pub fn layers(&self) -> &Vec<Layer> {
&self.layers
}
}