#include "MapSource.h" #include <gd.h> void MapSource::process_cmd_line_args(int argc,char *argv[]) { std::string bbox=""; argc--; argv++; width=800; height=600; while(argc>0) { if(argv[0][0]=='-' && strlen(argv[0])>1) { switch(argv[0][1]) { case 's': setSource(argv[1]); argv+=2; argc-=2; break; case 'w': width=atoi(argv[1]); argv+=2; argc-=2; break; case 'h': height=atoi(argv[1]); argv+=2; argc-=2; break; case 'x': xmlfile=argv[1]; argv+=2; argc-=2; break; case 'i': osmfile=argv[1]; argv+=2; argc-=2; break; case 'b': bbox=argv[1]; argv+=2; argc-=2; break; case 'z': zoom_start=atoi(argv[1]); argv+=2; argc-=2; break; case 'Z': zoom_end=atoi(argv[1]); argv+=2; argc-=2; break; case 't': tiled=true; argv+=1; argc-=1; break; case 'm': multirqst=true; argv+=1; argc-=1; break; case 'u': url=argv[1]; argv+=2; argc-=2; break; case 'o': outfile=argv[1]; argv+=2; argc-=2; break; case 'r': srtm=true; argv++; argc--; break; } } else { argv++; argc--; } } if(bbox!="") { typedef boost::tokenizer<boost::char_separator<char> > tokenizer; boost::char_separator<char> comma(","); tokenizer t (bbox,comma); int count=0; for(tokenizer::iterator i=t.begin(); i!=t.end(); i++) { if(count==0) w=atof(i->c_str()); else if (count==1) s=atof(i->c_str()); else if (count==2) e=atof(i->c_str()); else if (count==3) n=atof(i->c_str()); count++; } } if(zoom_end == -1) zoom_end = zoom_start; if(tiled) width=height=256+(32*2); } void MapSource::generateMaps() { GoogleProjection proj; if(tiled) { ScreenPos topLeft = (proj.fromLLToPixel(w,n,zoom_start)) , bottomRight = (proj.fromLLToPixel(e,s,zoom_start)) ; topLeft.x /= 256; topLeft.y /= 256; bottomRight.x /= 256; bottomRight.y /= 256; int x_fetch_freq, y_fetch_freq, x_fetches, y_fetches; if(multirqst) { // Gives a value approx equal to 0.1 lat/lon in southern UK x_fetch_freq = (int)(pow(2.0,zoom_start-11)); y_fetch_freq = (int)(pow(2.0,zoom_start-11)); x_fetches = ((bottomRight.x-topLeft.x) / x_fetch_freq)+1, y_fetches = ((bottomRight.y-topLeft.y) / y_fetch_freq)+1; } else { x_fetch_freq = bottomRight.x - topLeft.x; y_fetch_freq = bottomRight.y - topLeft.y; x_fetches = 1; y_fetches = 1; } fprintf(stderr,"topLeft: %d %d\n",topLeft.x,topLeft.y); fprintf(stderr,"bottomRight: %d %d\n",bottomRight.x,bottomRight.y); fprintf(stderr,"xfetches yfetches: %d %d\n",x_fetches, y_fetches); for(int xfetch=0; xfetch<x_fetches; xfetch++) { for (int yfetch=0; yfetch<y_fetches; yfetch++) { cerr<<"XFETCH="<<xfetch<<" YFETCH="<<yfetch<<endl; EarthPoint bottomL_LL = proj.fromPixelToLL( (topLeft.x+xfetch*x_fetch_freq)*256, ((topLeft.y+yfetch*y_fetch_freq) +y_fetch_freq)*256, zoom_start), topR_LL = proj.fromPixelToLL( ( (topLeft.x+xfetch*x_fetch_freq)+x_fetch_freq)*256, (topLeft.y+yfetch*y_fetch_freq) *256, zoom_start), bottomR_LL = proj.fromPixelToLL( ((topLeft.x+xfetch*x_fetch_freq)+ x_fetch_freq)*256, ((topLeft.y+yfetch*y_fetch_freq) +y_fetch_freq)*256, zoom_start), topL_LL = proj.fromPixelToLL( (topLeft.x+xfetch*x_fetch_freq)*256, (topLeft.y+yfetch*y_fetch_freq) *256, zoom_start); double w1 = min(bottomL_LL.x-0.01,topL_LL.x-0.01), s1 = min(bottomL_LL.y-0.01,bottomR_LL.y-0.01), e1 = max(bottomR_LL.x+0.01,topR_LL.x+0.01), n1 = max(topL_LL.y+0.01,topR_LL.y+0.01); parameters p; if(getSource()=="api") { std::ostringstream str; str<<w1<<","<<s1<<"," <<e1<<","<<n1; p["url"] = url; p["file"] = ""; p["bbox"] = str.str(); cerr<<"URL="<<str.str()<<endl; } else if (getSource()=="osm") { p["file"] = osmfile; } Map m (width, height); p["type"] ="osm"; load_map(m,xmlfile); setOSMLayers(m,p); if(srtm) { addSRTMLayers(m,w1,s1,e1,n1); } // lonToX() and latToY() give *pixel* coordinates // See email Chris Schmidt 12/02/09 double metres_per_pixel = (20037508.34/pow(2.0, 7+zoom_start)); for(int z=zoom_start; z<=zoom_end; z++) { EarthPoint bl,tr; int ZOOM_FCTR = (int)(pow(2.0,z-zoom_start)); for(int tileX= (topLeft.x+xfetch*x_fetch_freq)*ZOOM_FCTR; tileX< (topLeft.x+xfetch*x_fetch_freq+x_fetch_freq) *ZOOM_FCTR; tileX++) { for(int tileY=(topLeft.y+yfetch*y_fetch_freq) *ZOOM_FCTR; tileY<(topLeft.y+yfetch*y_fetch_freq+y_fetch_freq) *ZOOM_FCTR; tileY++) { cerr<<"x: " << tileX << " y: " << tileY <<" z: " << z << endl; image_32 buf(m.width(),m.height()); double metres_w =( (tileX*256.0) * metres_per_pixel ) - 20037814.088; double metres_s = 20034756.658 - ((tileY*256.0) * metres_per_pixel ); double metres_e = metres_w + (metres_per_pixel*256); double metres_n = metres_s + (metres_per_pixel*256); box2d<double> bb (metres_w-32*metres_per_pixel, metres_s-32*metres_per_pixel, metres_e+32*metres_per_pixel, metres_n+32*metres_per_pixel); m.zoom_to_box(bb); agg_renderer<image_32> r(m,buf); r.apply(); string filename=""; std::ostringstream str; str<< z<< "."<<tileX<<"." << tileY << ".png"; save_to_file<image_data_32>(buf.data(), "tmp.png","png"); FILE *in=fopen("tmp.png","r"); FILE *out=fopen(str.str().c_str(),"w"); gdImagePtr image, image2; image=gdImageCreateTrueColor(256,256); image2=gdImageCreateFromPng(in); gdImageCopy(image,image2,0,0,32,32,256,256); gdImagePng(image,out); gdImageDestroy(image2); gdImageDestroy(image); fclose(out); fclose(in); } } metres_per_pixel /= 2; } } } } else { // standard rendering Map m(width,height); parameters p; p["type"] = "osm"; p["file"] = osmfile; load_map(m,xmlfile); setOSMLayers(m,p); box2d<double> latlon= (hasBbox()) ? box2d<double>(w,s,e,n): m.getLayer(0).envelope(); EarthPoint bottomL_LL = GoogleProjection::fromLLToGoog(latlon.minx(),latlon.miny()), topR_LL = GoogleProjection::fromLLToGoog(latlon.maxx(),latlon.maxy()); box2d<double> bb = box2d<double>(bottomL_LL.x,bottomL_LL.y, topR_LL.x,topR_LL.y); m.zoom_to_box(bb); image_32 buf (m.width(), m.height()); agg_renderer<image_32> r(m,buf); r.apply(); save_to_file<image_data_32>(buf.data(),outfile,"png"); } } void MapSource::setOSMLayers(Map& m, const parameters &p) { parameters q; for(int count=0; count<m.layer_count(); count++) { q = m.getLayer(count).datasource()->params(); if(boost::get<std::string>(q["type"])=="osm") { m.getLayer(count).set_datasource (datasource_cache::instance()->create(p)); } } } void MapSource::addSRTMLayers(Map& m,double w,double s,double e,double n) { // Get the layers from the map vector<Layer> layers=m.layers(); cerr<<"***addSRTMLayers():w s e n="<<w<<" "<<s<<" "<<e<<" "<<n<<endl; int i=0; // Find the index of the SRTM layer while(i<layers.size() && layers[i].name()!="srtm") i++; // Return if we can't find an SRTM layer if(i==layers.size()) return; // Set the specific latlon shapefile for the first SRTM layer parameters p; p["type"] = "shape"; std::stringstream str; int lon=floor(w),lat=floor(s); str<<(lat<0 ? "S":"N")<<setw(2)<<setfill('0')<< (lat<0 ? -lat:lat)<< (lon>=0 ? "E":"W") << setw(3)<<setfill('0') <<(lon>=0 ? lon:-lon)<<"c10"; p["file"] = str.str(); cerr<<"ADDING SRTM LAYER: " << p["file"] << endl; m.getLayer(i).set_datasource(datasource_cache::instance()->create(p)); // do we have more than one srtm layer? if(floor(w) != floor(e) || floor(s) != floor(n)) { // remove all layers after the SRTM layer. This is because there // are multiple SRTM layers (if the current tile spans a lat/lon square // boundary) for(int j=i+1; j<layers.size(); j++) m.removeLayer(j); for(int lon=floor(w); lon<=floor(e); lon++) { for(int lat=floor(s); lat<=floor(n); lat++) { // if this isn't the bottom left lat/lon square, add another // SRTM layer for it if(lon!=floor(w) || lat!=floor(s)) { parameters p; p["type"] = "shape"; std::stringstream str; str<<(lat<0 ? "S":"N")<<setw(2)<<setfill('0')<< (lat<0 ? -lat:lat)<< (lon>=0 ? "E":"W") << setw(3)<<setfill('0') <<(lon>=0 ? lon:-lon)<<"c10"; p["file"] = str.str(); cerr<<"ADDING SRTM LAYER: " << p["file"] << endl; layer lyr("srtm_" + str.str()); lyr.add_style("contours"); lyr.add_style("contours-text"); lyr.set_datasource (datasource_cache::instance()->create(p)); m.addLayer(lyr); } } } // Add the other layers back for(int j=i+1; j<layers.size(); j++) m.addLayer(layers[j]); } }