Skip to content

Commit

Permalink
Replace hardcoded references with db::Config
Browse files Browse the repository at this point in the history
  • Loading branch information
erik committed Oct 12, 2023
1 parent de3a2e4 commit f528e7d
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 38 deletions.
37 changes: 25 additions & 12 deletions projects/hotpot/src/activity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,24 @@ use geo_types::{LineString, MultiLineString, Point};
use rusqlite::params;
use time::OffsetDateTime;

use crate::db;
use crate::db::encode_line;
use crate::simplify::simplify_line;
use crate::tile::{BBox, LngLat, Tile, WebMercator};
use crate::{DEFAULT_TILE_EXTENT, DEFAULT_ZOOM_LEVELS};

// TODO: not happy with the ergonomics of this.
struct TileClipper {
zoom: u8,
tile_extent: u16,
current: Option<(Tile, BBox)>,
tiles: HashMap<Tile, Vec<LineString<u16>>>,
}

impl TileClipper {
fn new(zoom: u8) -> Self {
fn new(zoom: u8, tile_extent: u16) -> Self {
Self {
zoom,
tile_extent,
tiles: HashMap::new(),
current: None,
}
Expand Down Expand Up @@ -69,14 +71,13 @@ impl TileClipper {

// [start, end] is at least partially contained within the current tile.
Some((a, b)) => {
let extent = self.tile_extent;
let line = self.last_line(&tile);
if line.0.is_empty() {
line.0
.push(a.to_pixel(&bbox, DEFAULT_TILE_EXTENT as u16).into());
line.0.push(a.to_pixel(&bbox, extent).into());
}

line.0
.push(b.to_pixel(&bbox, DEFAULT_TILE_EXTENT as u16).into());
line.0.push(b.to_pixel(&bbox, extent).into());

// If we've modified the end point, we've left the current tile.
if b != end {
Expand Down Expand Up @@ -126,10 +127,22 @@ pub struct RawActivity {
impl RawActivity {
/// How far apart two points can be before we consider them to be
/// a separate line segment.
///
/// TODO: move to db config?
const MAX_POINT_DISTANCE: f64 = 5000.0;

pub fn clip_to_tiles(&self, zooms: &[u8], trim_dist: f64) -> ClippedTiles {
let mut clippers: Vec<_> = zooms.iter().map(|zoom| TileClipper::new(*zoom)).collect();
pub fn clip_to_tiles(
&self,
db::Config {
ref zoom_levels,
ref trim_dist,
ref tile_extent,
}: &db::Config,
) -> ClippedTiles {
let mut clippers: Vec<_> = zoom_levels
.iter()
.map(|z| TileClipper::new(*z, *tile_extent as u16))
.collect();

for line in self.tracks.iter() {
let points: Vec<_> = line
Expand All @@ -149,14 +162,14 @@ impl RawActivity {
let start_idx = points
.iter()
.enumerate()
.find(|(_, pt)| pt.0.euclidean_distance(first) >= trim_dist)
.find(|(_, pt)| pt.0.euclidean_distance(first) >= *trim_dist)
.map(|(i, _)| i);

let end_idx = points
.iter()
.rev()
.enumerate()
.find(|(_, pt)| pt.0.euclidean_distance(last) >= trim_dist)
.find(|(_, pt)| pt.0.euclidean_distance(last) >= *trim_dist)
.map(|(i, _)| points.len() - 1 - i);

if let Some((i, j)) = start_idx.zip(end_idx) {
Expand Down Expand Up @@ -386,7 +399,7 @@ pub fn upsert(
conn: &mut rusqlite::Connection,
name: &str,
activity: &RawActivity,
trim_dist: f64,
config: &db::Config,
) -> Result<i64> {
let mut insert_tile = conn.prepare_cached(
"\
Expand Down Expand Up @@ -418,7 +431,7 @@ pub fn upsert(
)?;
}

let tiles = activity.clip_to_tiles(&DEFAULT_ZOOM_LEVELS, trim_dist);
let tiles = activity.clip_to_tiles(&config);
for (tile, line) in tiles.iter() {
let coords = encode_line(&simplify_line(&line.0, 4.0))?;
insert_tile.insert(params![activity_id, tile.z, tile.x, tile.y, coords])?;
Expand Down
7 changes: 5 additions & 2 deletions projects/hotpot/src/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ use rusqlite::{params, ToSql};
use serde::Deserialize;
use time::{Date, OffsetDateTime};

use crate::{DEFAULT_TILE_EXTENT, DEFAULT_TRIM_DIST, DEFAULT_ZOOM_LEVELS};

const SCHEMA: &str = "\
CREATE TABLE IF NOT EXISTS config (
key TEXT NOT NULL PRIMARY KEY
Expand Down Expand Up @@ -112,6 +110,11 @@ fn apply_schema(conn: &mut rusqlite::Connection) -> Result<()> {
Ok(())
}


const DEFAULT_TILE_EXTENT: u32 = 2048;
const DEFAULT_ZOOM_LEVELS: [u8; 5] = [2, 6, 10, 14, 16];
const DEFAULT_TRIM_DIST: f64 = 200.0;

pub struct Config {
/// Zoom levels that we store activity tiles for.
pub zoom_levels: Vec<u8>,
Expand Down
16 changes: 3 additions & 13 deletions projects/hotpot/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ mod simplify;
mod tile;
mod web;

// TODO: Remove all direct uses of these, replace with DB config.
const DEFAULT_ZOOM_LEVELS: [u8; 5] = [2, 6, 10, 14, 16];
const DEFAULT_TILE_EXTENT: u32 = 2048;
const DEFAULT_TRIM_DIST: f64 = 200.0;

#[derive(Subcommand)]
enum Commands {
/// Import activities from GPX, TCX, and FIT files.
Expand Down Expand Up @@ -131,7 +126,7 @@ enum Commands {
#[derive(Args)]
struct GlobalOpts {
/// Path to database
#[arg(default_value = "./hotpot.sqlite3")]
#[arg(short = 'D', long = "db", default_value = "./hotpot.sqlite3")]
db_path: PathBuf,
/// Enable verbose logging
#[arg(short, long)]
Expand Down Expand Up @@ -386,13 +381,8 @@ fn import_activities(p: &Path, db: &Database, prop_source: &AttributeSource) ->
prop_source.enrich(&path, &mut activity);

let mut conn = pool.get().expect("db connection pool timed out");
activity::upsert(
&mut conn,
path.to_str().unwrap(),
&activity,
db.config.trim_dist,
)
.expect("insert activity");
activity::upsert(&mut conn, path.to_str().unwrap(), &activity, &db.config)
.expect("insert activity");

num_imported.fetch_add(1, Ordering::Relaxed);
},
Expand Down
17 changes: 9 additions & 8 deletions projects/hotpot/src/raster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use rusqlite::{params, ToSql};

use crate::db::{decode_line, ActivityFilter, Database};
use crate::tile::{Tile, TileBounds};
use crate::DEFAULT_TILE_EXTENT;

pub static DEFAULT_GRADIENT: Lazy<LinearGradient> = Lazy::new(|| {
LinearGradient::from_stops(&[
Expand Down Expand Up @@ -52,21 +51,23 @@ struct TileRaster {
bounds: TileBounds,
scale: u32,
width: u32,
tile_extent: u32,
pixels: Vec<u8>,
}

impl TileRaster {
fn new(tile: Tile, source: TileBounds, width: u32) -> Self {
fn new(tile: Tile, source: TileBounds, width: u32, tile_extent: u32) -> Self {
// TODO: support upscaling
assert!(width <= DEFAULT_TILE_EXTENT, "Upscaling not supported");
assert!(width <= tile_extent, "Upscaling not supported");
assert!(width.is_power_of_two(), "width must be power of two");
assert!(source.z >= tile.z, "source zoom must be >= target zoom");

let zoom_steps = (source.z - tile.z) as u32;
let width_steps = DEFAULT_TILE_EXTENT.ilog2() - width.ilog2();
let width_steps = tile_extent.ilog2() - width.ilog2();

Self {
width,
tile_extent,
pixels: vec![0; (width * width) as usize],
bounds: source,
scale: zoom_steps + width_steps,
Expand All @@ -77,15 +78,15 @@ impl TileRaster {
debug_assert_eq!(source_tile.z, self.bounds.z);

// Origin of source tile within target tile
let x_offset = DEFAULT_TILE_EXTENT * (source_tile.x - self.bounds.xmin);
let y_offset = DEFAULT_TILE_EXTENT * (source_tile.y - self.bounds.ymin);
let x_offset = self.tile_extent * (source_tile.x - self.bounds.xmin);
let y_offset = self.tile_extent * (source_tile.y - self.bounds.ymin);

let mut prev = None;
for Coord { x, y } in coords {
// Translate (x,y) to location in target tile.
// [0..(width * STORED_TILE_WIDTH)]
let x = x + x_offset;
let y = (DEFAULT_TILE_EXTENT - y) + y_offset;
let y = (self.tile_extent - y) + y_offset;

// Scale the coordinates back down to [0..width]
let x = x >> self.scale;
Expand Down Expand Up @@ -183,7 +184,7 @@ pub fn render_tile(
.ok_or_else(|| anyhow!("no source level for tile: {:?}", tile))?;

let bounds = TileBounds::from(zoom_level, &tile);
let mut raster = TileRaster::new(tile, bounds, width);
let mut raster = TileRaster::new(tile, bounds, width, db.config.tile_extent);

let mut have_activity = false;

Expand Down
5 changes: 3 additions & 2 deletions projects/hotpot/src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ struct RenderQueryParams {
before: Option<Date>,
#[serde(default, with = "crate::date::parse")]
after: Option<Date>,
// TODO: parse as a `PropertyFilter` directly using `with` annotation
// TODO: support multiple filters which get AND'd together
// TODO: parse as a `PropertyFilter` directly using custom `with` annotation
filter: Option<String>,
}

Expand Down Expand Up @@ -233,7 +234,7 @@ async fn upload_activity(
let mut conn = db.connection().unwrap();
let id = format!("upload:{}", file_name);

activity::upsert(&mut conn, &id, &activity, db.config.trim_dist).unwrap();
activity::upsert(&mut conn, &id, &activity, &db.config).unwrap();
}
}

Expand Down
2 changes: 1 addition & 1 deletion projects/hotpot/src/web/strava.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ async fn receive_webhook(
tracks: MultiLineString::from(polyline),
properties: activity.properties,
},
db.config.trim_dist,
&db.config,
)
.unwrap();

Expand Down

0 comments on commit f528e7d

Please sign in to comment.