package com.nutiteq.advancedmap3;
import android.os.Bundle;
import android.util.Log;
import com.nutiteq.datasources.HTTPTileDataSource;
import com.nutiteq.datasources.PersistentCacheTileDataSource;
import com.nutiteq.datasources.TileDataSource;
import com.nutiteq.layers.TorqueTileLayer;
import com.nutiteq.vectortiles.CartoCSSStyleSet;
import com.nutiteq.vectortiles.TorqueTileDecoder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* A sample demonstrating how to use CartoDB Torque tiles with CartoCSS styling
*/
public class CartoDBTorqueActivity extends VectorMapSampleBaseActivity {
private static final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor();
private static final long TORQUE_FRAMETIME_MS = 100;
private TorqueTileLayer torqueTileLayer;
private boolean stopped;
@Override
protected void onCreate(Bundle savedInstanceState) {
// MapSampleBaseActivity creates and configures mapView
super.onCreate(savedInstanceState);
String cartoCss = "#layer {\n"+
" comp-op: lighten;\n"+
" marker-type:ellipse;\n"+
" marker-width: 10;\n"+
" marker-fill: #FEE391;\n"+
" [value > 2] { marker-fill: #FEC44F; }\n"+
" [value > 3] { marker-fill: #FE9929; }\n"+
" [value > 4] { marker-fill: #EC7014; }\n"+
" [value > 5] { marker-fill: #CC4C02; }\n"+
" [value > 6] { marker-fill: #993404; }\n"+
" [value > 7] { marker-fill: #662506; }\n"+
"\n"+
" [frame-offset = 1] {\n"+
" marker-width: 20;\n"+
" marker-fill-opacity: 0.1;\n"+
" }\n"+
" [frame-offset = 2] {\n"+
" marker-width: 30;\n"+
" marker-fill-opacity: 0.05;\n"+
" }\n"+
"}\n";
// magic query to create torque tiles
String query = "WITH par \n" +
"AS (SELECT Cdb_xyz_resolution({zoom}) * 1 AS res,\n" +
"256 / 1 AS tile_size,\n" +
"Cdb_xyz_extent({x}, {y}, {zoom}) AS ext),\n" +
"cte\n" +
"AS (SELECT St_snaptogrid(i.the_geom_webmercator, p.res) g,\n" +
" Count(cartodb_id) c,\n" +
" Floor(( Date_part('epoch', date) - -1796072400 ) / 476536.5) d\n" +
"FROM (SELECT *\n" +
" FROM ow) i,\n" +
" par p\n" +
" WHERE i.the_geom_webmercator && p.ext\n" +
" GROUP BY g, d)\n" +
"SELECT ( St_x(g) - St_xmin(p.ext) ) / p.res x__uint8,\n" +
" ( St_y(g) - St_ymin(p.ext) ) / p.res y__uint8,\n" +
" Array_agg(c) vals__uint8,\n" +
" Array_agg(d) dates__uint16\n" +
"FROM cte,\n" +
" par p\n" +
"WHERE ( St_y(g) - St_ymin(p.ext) ) / p.res < tile_size\n" +
" AND ( St_x(g) - St_xmin(p.ext) ) / p.res < tile_size\n" +
"GROUP BY x__uint8,\n" +
" y__uint8 ";
String encodedQuery = null;
try {
encodedQuery = URLEncoder.encode(query.replace("\n",""), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
encodedQuery = "WITH%20par%20AS%20(%20%20SELECT%20CDB_XYZ_Resolution({zoom})*1%20as%20res%2C%20%20256%2F1%20as%20tile_size%2C%20CDB_XYZ_Extent({x}%2C%20{y}%2C%20{zoom})%20as%20ext%20)%2Ccte%20AS%20(%20%20%20SELECT%20ST_SnapToGrid(i.the_geom_webmercator%2C%20p.res)%20g%2C%20count(cartodb_id)%20c%2C%20floor((date_part(%27epoch%27%2C%20date)%20-%20-1796072400)%2F476536.5)%20d%20%20FROM%20(select%20*%20from%20ow)%20i%2C%20par%20p%20%20%20WHERE%20i.the_geom_webmercator%20%26%26%20p.ext%20%20%20GROUP%20BY%20g%2C%20d)%20SELECT%20(st_x(g)-st_xmin(p.ext))%2Fp.res%20x__uint8%2C%20%20%20%20%20%20%20%20(st_y(g)-st_ymin(p.ext))%2Fp.res%20y__uint8%2C%20array_agg(c)%20vals__uint8%2C%20array_agg(d)%20dates__uint16%20FROM%20cte%2C%20par%20p%20where%20(st_y(g)-st_ymin(p.ext))%2Fp.res%20%3C%20tile_size%20and%20(st_x(g)-st_xmin(p.ext))%2Fp.res%20%3C%20tile_size%20GROUP%20BY%20x__uint8%2C%20y__uint8&last_updated=1970-01-01T00%3A00%3A00.000Z";
// define datasource with the query
HTTPTileDataSource torqueDataSource = new HTTPTileDataSource(0, 14,
"http://viz2.cartodb.com/api/v2/sql?q="+encodedQuery+"&cache_policy=persist");
// create persistent cache to make it faster
String cacheFile = getExternalFilesDir(null)+"/torque_tile_cache.db";
Log.i(Const.LOG_TAG, "cacheFile = " + cacheFile);
TileDataSource cacheDataSource = new PersistentCacheTileDataSource(torqueDataSource, cacheFile);
// Create CartoCSS style from Torque points
CartoCSSStyleSet torqueStyleSet = new CartoCSSStyleSet(cartoCss);
// Create tile decoder and Torque layer
TorqueTileDecoder torqueDecoder = new TorqueTileDecoder(torqueStyleSet);
torqueTileLayer = new TorqueTileLayer(cacheDataSource, torqueDecoder);
mapView.getLayers().add(torqueTileLayer);
// Start updating frames for animation
worker.schedule(task, TORQUE_FRAMETIME_MS, TimeUnit.MILLISECONDS);
mapView.setZoom(1, 0);
}
@Override
protected void onStop() {
synchronized (worker) {
stopped = true;
}
super.onStop();
}
private Runnable task = new Runnable() {
public void run() {
synchronized (worker) {
int frameNr = (torqueTileLayer.getFrameNr()+1) % torqueTileLayer.getFrameCount();
torqueTileLayer.setFrameNr(frameNr);
Log.d(Const.LOG_TAG, "torque frame " + torqueTileLayer.getFrameNr()+ " of "+torqueTileLayer.getFrameCount());
if (!stopped) {
worker.schedule(task, TORQUE_FRAMETIME_MS, TimeUnit.MILLISECONDS);
}
}
}
};
}