From 19cf7bee5db279ae7e489287b32d07ae75147d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20Ka=CC=88fer?= Date: Fri, 24 Jun 2011 09:56:45 +0200 Subject: [PATCH] add dependency to sphericalmercator so that we can move the .info method to mbtiles --- lib/mbtiles.js | 100 ++++++++++++++++++++++++++++++++++++++++++++++++- package.json | 1 + 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/lib/mbtiles.js b/lib/mbtiles.js index deaed98..fdb6b8f 100644 --- a/lib/mbtiles.js +++ b/lib/mbtiles.js @@ -4,12 +4,14 @@ var _ = require('underscore'), crypto = require('crypto'), zlib = require('zlib'), get = require('get'), + sm = new (require('sphericalmercator')), sqlite3 = require('sqlite3'); // MBTiles // ------- // MBTiles class for doing common operations (schema setup, tile reading, // insertion, etc.) +module.exports = MBTiles; function MBTiles(filename, callback) { var mbtiles = this; this.filename = filename; @@ -306,4 +308,100 @@ MBTiles.prototype.metadata = function(key, callback) { }); }; -module.exports = MBTiles; +// Extend `MBTiles` class with an `info` method for retrieving metadata and +// performing fallback queries if certain keys (like `bounds`, `minzoom`, +// `maxzoom`) have not been provided. +MBTiles.prototype.info = function(callback) { + var that = this; + var info = {}; + info.basename = path.basename(that.filename); + info.id = info.basename.replace(path.extname(that.filename), ''); + Step(function() { + var end = this; + that.db.all('SELECT name, value FROM metadata', function(err, rows) { + if (rows) for (var i = 0; i < rows.length; i++) { + info[rows[i].name] = rows[i].value; + } + end(err); + }); + }, + // Determine min/max zoom if needed + function(err) { + if (err) throw err; + if (info.maxzoom !== undefined + && info.minzoom !== undefined) return this(); + + var group = this.group(); + + var zoomquery = that.db.prepare('SELECT zoom_level FROM tiles ' + + 'WHERE zoom_level = ? LIMIT 1'); + for (var i = 0; i < 30; i++) { + zoomquery.get(i, group()); + } + zoomquery.finalize(); + }, + function(err, rows) { + if (err) throw err; + if (rows) { + var zooms = _(rows).chain() + .reject(_.isUndefined) + .pluck('zoom_level') + .value(); + info.minzoom = zooms.shift(); + info.maxzoom = zooms.length ? zooms.pop() : info.minzoom; + } + this(); + }, + // Determine bounds if needed + function(err) { + if (err) throw err; + if (info.bounds) return this(); + if (typeof info.minzoom === 'undefined') return this(); + + var next = this; + Step( + function() { + that.db.get( + 'SELECT MAX(tile_column) AS maxx, ' + + 'MIN(tile_column) AS minx, MAX(tile_row) AS maxy, ' + + 'MIN(tile_row) AS miny FROM tiles ' + + 'WHERE zoom_level = ?', + info.minzoom, + this + ); + }, + function(err, row) { + if (!err && row) { + // @TODO this breaks a little at zoom level zero + var urTile = sm.bbox(row.maxx, row.maxy, info.minzoom, true); + var llTile = sm.bbox(row.minx, row.miny, info.minzoom, true); + // @TODO bounds are limited to "sensible" values here + // as sometimes tilesets are rendered with "negative" + // and/or other extremity tiles. Revisit this if there + // are actual use cases for out-of-bounds bounds. + info.bounds = [ + llTile[0] > -180 ? llTile[0] : -180, + llTile[1] > -90 ? llTile[1] : -90, + urTile[2] < 180 ? urTile[2] : 180, + urTile[3] < 90 ? urTile[3] : 90 + ].join(','); + } + next(); + } + ); + }, + // Return info + function(err) { + if (err) return callback(err); + var range = parseInt(info.maxzoom) - parseInt(info.minzoom); + info.minzoom = parseInt(info.minzoom); + info.maxzoom = parseInt(info.maxzoom); + info.bounds = _(info.bounds.split(',')).map(parseFloat); + info.center = [ + (info.bounds[2] - info.bounds[0]) / 2 + info.bounds[0], + (info.bounds[3] - info.bounds[1]) / 2 + info.bounds[1], + (range <= 1) ? info.maxzoom : Math.floor(range * 0.5) + info.minzoom + ]; + callback(null, info); + }); +}; diff --git a/package.json b/package.json index 66194f7..0083842 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "optimist": "0.2.x", "sqlite3": "2.0.x", "step": "0.0.x", + "sphericalmercator": "1.0.x", "get": "0.3.x", "underscore": "1.1.x", "zlib": "1.0.x"