This compiles, but I recommend you to run clippy
to adapt the code to more best current practices. I changed some dependencies to more modern equivalents. Also, I've never used the postgres crate and don't know if it will work reading and writing the json. Please test thoroughly.
/*
[dependencies]
postgres = {version="0.19.7", features=["with-serde_json-1"]}
bitflags = "1.3.2"
serde_json = "1.0.116"
byteorder = "1"
*/
use postgres::NoTls;
use bitflags::bitflags;
use std::cmp;
use std::default::Default;
use std::fs::File;
use std::io;
use std::io::Seek;
use std::io::SeekFrom;
use std::io::Write;
use std::path::Path;
use byteorder::LittleEndian;
use byteorder::WriteBytesExt;
use serde_json::Value;
use postgres::Client;
use postgres::{Row, Statement, Transaction};
use self::InsertResult::Full;
use self::InsertResult::Inserted;
use self::NodeData::Leaf;
use self::NodeData::SubNodes;
// as much as you can fit in a 512 byte block
static DEGREE: usize = 25;
#[derive()]
enum InsertResult<T> {
Inserted(Node<T>),
Full(Node<T>, Node<T>),
}
#[derive(Copy, Clone, Default)]
struct Point {
x: isize,
y: isize,
}
#[derive(Copy, Clone, Default)]
struct Rect {
x0: isize,
y0: isize,
x1: isize,
y1: isize,
}
#[derive()]
enum NodeData<T> {
SubNodes(Vec<Node<T>>),
Leaf(T),
}
#[derive()]
struct Node<T> {
rect: Rect,
sub: NodeData<T>,
}
bitflags! {
struct WayFlags: u8 {
const VANILLA = 0x00;
const FRIENDLY = 0x01;
const HOSTILE = 0x02;
const ROUTE = 0x04;
}
}
struct Way {
flags: WayFlags,
name: String,
nodes: Vec<Point>,
}
impl Rect {
fn height(&self) -> isize {
return self.y1 - self.y0;
}
fn width(&self) -> isize {
return self.x1 - self.x0;
}
fn center(&self) -> Point {
return Point {
x: self.x0 + (self.width() / 2),
y: self.y0 + (self.height() / 2),
};
}
fn needed_growth(&self, rect: &Rect) -> isize {
let newrect = self.grow(rect);
let diff = (newrect.width() * newrect.height()) - (self.width() * self.height());
return cmp::max(0, diff);
}
fn grow(&self, rect: &Rect) -> Rect {
return Rect {
x0: cmp::min(self.x0, rect.x0),
y0: cmp::min(self.y0, rect.y0),
x1: cmp::max(self.x1, rect.x1),
y1: cmp::max(self.y1, rect.y1),
};
}
}
impl<T: TreeWriter> Node<T> {
fn new(rect: Rect) -> Node<T> {
return Node {
rect: rect,
sub: SubNodes(Vec::with_capacity(DEGREE)),
};
}
fn is_leaf(&self) -> bool {
return match self.sub {
Leaf(_) => true,
SubNodes(_) => false,
};
}
fn subnodes(&self) -> &Vec<Node<T>> {
return match self.sub {
Leaf(_) => panic!("leaf has no nodes"),
SubNodes(ref n) => n,
};
}
fn mut_subnodes(&mut self) -> &mut Vec<Node<T>> {
return match self.sub {
Leaf(_) => panic!("leaf has no nodes"),
SubNodes(ref mut n) => n,
};
}
fn move_subnodes(self) -> Vec<Node<T>> {
return match self.sub {
Leaf(_) => panic!("leaf has no nodes"),
SubNodes(n) => n,
};
}
fn mut_leaf(&mut self) -> &mut T {
return match self.sub {
Leaf(ref mut l) => l,
SubNodes(_) => panic!("Not a leaf"),
};
}
fn split(self) -> [Node<T>; 2] {
let rect = self.rect;
let mut subnodes = self.move_subnodes();
let len = subnodes.len();
if rect.width() > rect.height() {
subnodes.sort_by(|n, m| n.rect.center().x.cmp(&m.rect.center().x));
} else {
subnodes.sort_by(|n, m| n.rect.center().y.cmp(&m.rect.center().y));
}
let b = subnodes.split_off(len / 2);
let a = subnodes;
let mut n1: Node<T> = Node::new(Default::default());
let mut n2: Node<T> = Node::new(Default::default());
n1.sub = SubNodes(a);
n1.update_rect();
n2.sub = SubNodes(b);
n2.update_rect();
return [n1, n2];
}
fn update_rect(&mut self) {
let init: Option<Rect> = None;
self.rect = self
.subnodes()
.iter()
.fold(init, |i, n| match i {
None => Some(n.rect),
Some(r) => Some(r.grow(&n.rect)),
})
.unwrap();
}
fn best_node(&mut self, rect: &Rect) -> Node<T> {
let (index, _) = self
.subnodes()
.iter()
.enumerate()
.filter(|(_, n)| !n.is_leaf())
.min_by_key(|(_, n)| n.rect.needed_growth(rect))
.expect("no insertable subs");
//println!("best is {} of {}", index, self.subnodes().len());
return self.mut_subnodes().swap_remove(index);
}
fn insert_(mut self, new: Node<T>) -> InsertResult<T> {
if self.subnodes().iter().any(|n| !n.is_leaf()) {
// ***************************
// There are subnodes, descend.
//println!("subs");
let node = self.best_node(&new.rect);
match node.insert_(new) {
Inserted(newchild) => {
// ***************************
// Node inserted. Back out.
//println!("inserted, now {} children", self.subnodes().len());
assert!(self.subnodes().len() < DEGREE);
self.mut_subnodes().push(newchild);
self.update_rect();
return Inserted(self);
}
Full(mut newchild, new) => {
// ***************************
// Child full. Split.
// This is the tricky part.
//println!("child full");
newchild.mut_subnodes().push(new);
let [n1, n2] = newchild.split();
//println!("n1 = {}, n2 = {}", n1.subnodes().len(), n2.subnodes().len());
assert!(self.subnodes().len() < DEGREE);
self.mut_subnodes().push(n1);
if self.subnodes().len() < DEGREE {
self.mut_subnodes().push(n2);
self.update_rect();
//println!("inserted after split, now {} children", self.subnodes().len());
return Inserted(self);
} else {
self.update_rect();
//println!("full after split, now {} children", self.subnodes().len());
return Full(self, n2);
}
}
}
} else if self.subnodes().len() < DEGREE {
// ***************************
// Add the new node at this level
//println!("inserting in node with {} children", self.subnodes().len());
self.rect = self.rect.grow(&new.rect);
self.mut_subnodes().push(new);
return Inserted(self);
} else {
// ***************************
// This node is full
//println!("full");
return Full(self, new);
}
}
fn insert(self, new: Node<T>) -> Node<T> {
match self.insert_(new) {
Inserted(node) => return node,
Full(mut node, new) => {
println!("root full");
let mut newroot: Node<T> = Node::new(node.rect);
node.mut_subnodes().push(new);
let [n1, n2] = node.split();
newroot.mut_subnodes().push(n1);
newroot.mut_subnodes().push(n2);
newroot.update_rect();
return newroot;
}
}
}
}
trait TreeWriter {
fn write<U>(&self, w: &mut U) -> io::Result<u64>
where
U: Write + Seek;
}
impl TreeWriter for Point {
fn write<U>(&self, w: &mut U) -> io::Result<u64>
where
U: Write + Seek,
{
let offset = w.seek(std::io::SeekFrom::Current(0))?;
w.write_i32::<LittleEndian>(self.x as i32)?;
w.write_i32::<LittleEndian>(self.y as i32)?;
return Ok(offset);
}
}
impl TreeWriter for Rect {
fn write<U>(&self, w: &mut U) -> io::Result<u64>
where
U: Write + Seek,
{
let offset = w.seek(std::io::SeekFrom::Current(0))?;
w.write_i32::<LittleEndian>(self.x0 as i32)?;
w.write_i32::<LittleEndian>(self.y0 as i32)?;
w.write_i32::<LittleEndian>(self.x1 as i32)?;
w.write_i32::<LittleEndian>(self.y1 as i32)?;
return Ok(offset);
}
}
fn seek_block<S: Seek>(w: &mut S, blocksize: u64) -> io::Result<u64> {
// seek forward to the nearest 512 bytes
let bsbits = blocksize - 1;
let offset = w.seek(std::io::SeekFrom::Current(0))? + bsbits & !bsbits;
assert!(offset % blocksize == 0);
w.seek(SeekFrom::Start(offset))?;
return Ok(offset);
}
impl TreeWriter for Node<Way> {
fn write<U>(&self, w: &mut U) -> io::Result<u64>
where
U: Write + Seek,
{
match self.sub {
Leaf(ref data) => {
let offset = seek_block(w, 512)?;
w.write_u8(0)?; // leaf node
data.write(w)?;
return Ok(offset);
}
SubNodes(ref subs) => {
let offsets: Vec<u64> = subs.iter().filter_map(|sub| sub.write(w).ok()).collect();
let offset = seek_block(w, 512)?;
w.write_u8(offsets.len() as u8)?;
for (o, sub) in offsets.into_iter().zip(subs.iter()) {
w.write_u32::<LittleEndian>(o as u32)?;
sub.rect.write(w)?;
}
return Ok(offset);
}
}
}
}
impl TreeWriter for Way {
fn write<U>(&self, w: &mut U) -> io::Result<u64>
where
U: Write + Seek,
{
let offset = w.seek(std::io::SeekFrom::Current(0))?;
w.write_u16::<LittleEndian>(self.nodes.len() as u16)?;
w.write_u8(self.name.len() as u8)?;
w.write_u8(self.flags.bits())?;
w.write_all(self.name.as_bytes())?;
w.write_u8(0)?; // C null byte
// allign points to 512 byte block
seek_block(w, 8)?;
for o in self.nodes.iter() {
o.write(w)?;
}
return Ok(offset);
}
}
fn query(conn: &mut Transaction) -> Statement {
return conn
.prepare(
"SELECT w.id,
ST_X(n.geom), ST_Y(n.geom),
ST_XMIN(w.bbox), ST_YMIN(w.bbox),
ST_XMAX(w.bbox), ST_YMAX(w.bbox),
HSTORE_TO_JSON(w.tags)
FROM way_nodes as wn
INNER JOIN nodes as n ON n.id = wn.node_id
INNER JOIN ways as w ON w.id = wn.way_id
ORDER BY wn.way_id, wn.sequence_id",
)
.unwrap();
}
fn get_fixedpoint(row: &Row, idx: usize) -> isize {
let fl: f64 = row.get(idx);
return (fl * 10000000.0) as isize;
}
fn parse_hstore(row: &Row) -> (String, WayFlags) {
let text = row.get(7);
let data = match text {
Some(Value::Object(m)) => m,
_ => panic!("No JSON in hstore"),
};
let name = match data.get(&String::from("name")) {
Some(&Value::String(ref s)) => s.clone(),
_ => String::new(),
};
let highway = match data.get(&String::from("highway")) {
Some(&Value::String(ref s)) if s.as_str() == "motorway" => WayFlags::HOSTILE,
Some(&Value::String(ref s)) if s.as_str() == "trunk" => WayFlags::HOSTILE,
Some(&Value::String(ref s)) if s.as_str() == "primary" => WayFlags::HOSTILE,
Some(&Value::String(ref s)) if s.as_str() == "residential" => WayFlags::FRIENDLY,
Some(&Value::String(ref s)) if s.as_str() == "unclassified" => WayFlags::FRIENDLY,
Some(&Value::String(ref s)) if s.as_str() == "cycleway" => WayFlags::FRIENDLY,
_ => WayFlags::VANILLA,
};
let bicycle = match data.get(&String::from("bicycle")) {
Some(&Value::String(ref s)) if s.as_str() == "no" => WayFlags::HOSTILE,
Some(&Value::String(ref s)) if s.as_str() == "yes" => WayFlags::FRIENDLY,
Some(&Value::String(ref s)) if s.as_str() == "designated" => WayFlags::FRIENDLY,
_ => WayFlags::VANILLA,
};
let cycleway = match data.get(&String::from("cycleway")) {
Some(_) => WayFlags::FRIENDLY,
_ => WayFlags::VANILLA,
};
let bicycle_road = match data.get(&String::from("bicycle_road")) {
Some(_) => WayFlags::FRIENDLY,
_ => WayFlags::VANILLA,
};
return (name, highway | cycleway | bicycle | bicycle_road);
}
fn main() {
let mut conn = Client::connect("postgres://pepijndevos@localhost/osm", NoTls).unwrap();
let mut trans = conn.transaction().unwrap();
let mut root: Node<Way> = Node::new(Default::default());
let mut current_id: Option<i64> = None;
let mut current_node: Option<Node<Way>> = None;
let query = query(&mut trans);
let portal = trans.bind(&query, &[]).unwrap();
for row in trans.query_portal(&portal, 2000).unwrap() {
match current_id {
i @ Some(_) if i == row.get(0) => {
current_node = match current_node {
Some(mut node) => {
node.mut_leaf().nodes.push(Point {
x: get_fixedpoint(&row, 1),
y: get_fixedpoint(&row, 2),
});
Some(node)
}
None => None,
}
}
_ => {
match current_node {
Some(node) => {
root = root.insert(node);
//println!("#########################");
}
None => (),
}
let (name, flags) = parse_hstore(&row);
current_id = Some(row.get(0));
current_node = Some(Node {
rect: Rect {
x0: get_fixedpoint(&row, 3),
y0: get_fixedpoint(&row, 4),
x1: get_fixedpoint(&row, 5),
y1: get_fixedpoint(&row, 6),
},
sub: Leaf(Way {
flags: flags,
name: name,
nodes: vec![Point {
x: get_fixedpoint(&row, 1),
y: get_fixedpoint(&row, 2),
}],
}),
});
}
}
}
let ref mut f = File::create(&Path::new("data.bin")).unwrap();
f.seek(SeekFrom::Start(4)).unwrap();
let start = root.write(f).unwrap();
f.seek(SeekFrom::Start(0)).unwrap();
f.write_u32::<LittleEndian>(start as u32).unwrap();
}
#[test]
fn needed_growth_test() {
let r1 = Rect {
x0: 0,
y0: 0,
x1: 100,
y1: 100,
};
let r2 = Rect {
x0: 0,
y0: 0,
x1: 100,
y1: 101,
};
let r3 = Rect {
x0: 0,
y0: 0,
x1: 101,
y1: 101,
};
let r4 = Rect {
x0: -1,
y0: -1,
x1: 101,
y1: 101,
};
assert_eq!(r1.needed_growth(&r2), 100);
assert_eq!(r1.needed_growth(&r3), 201);
assert_eq!(r1.needed_growth(&r4), 404);
}
#[test]
fn grow_test() {
let r1 = Rect {
x0: 0,
y0: 0,
x1: 100,
y1: 100,
};
let r2 = Rect {
x0: 200,
y0: 200,
x1: 200,
y1: 200,
};
let g = r1.grow(&r2);
assert_eq!(g.x0, 0);
assert_eq!(g.y0, 0);
assert_eq!(g.x1, 200);
assert_eq!(g.y1, 200);
}
#[test]
fn split_test() {
let root: Node<Point> = Node::new(Rect {
x0: 0,
y0: 0,
x1: 100,
y1: 100,
});
let newroot = root
.insert(Node {
rect: Rect {
x0: 0,
y0: 0,
x1: 50,
y1: 50,
},
sub: Leaf(Point { x: 0, y: 0 }),
})
.insert(Node {
rect: Rect {
x0: 50,
y0: 50,
x1: 100,
y1: 100,
},
sub: Leaf(Point { x: 0, y: 0 }),
});
let [n1, n2] = newroot.split();
assert_eq!(n1.subnodes().len(), 1);
assert_eq!(n2.subnodes().len(), 1);
}