URL의 첫 번째 부분은 타일 서버를 지정합니다. 타일 좌표는 일반적으로 /zoom/x/y.png 형식의 꼬리로 지정됩니다. 일부 타일 서버는 특정 스타일시트를 지정하기 위해 디렉터리(e.g. "/cycle/")를 사용할 수 있습니다. (역사적으로 여러 서브도메인이 제공되어 각 호스트에 대한 동시에 열릴 수 있는 HTTP 연결 수의 브라우저 제한을 회피했지만, 현대 브라우저에서는 덜 중요합니다 - 예: a.tile, b.tile, c.tile).
This returns the NW-corner of the square. Use the function with xtile+1 and/or ytile+1 to get the other corners. With xtile+0.5 & ytile+0.5 it will return the center of the tile.
Same as the Python implementation above, this returns the NW-corner of the square. Use the function with xtile+1 and/or ytile+1 to get the other corners. With xtile+0.5 & ytile+0.5 it will return the center of the tile.
useMath::Trig;subProject{my($X,$Y,$Zoom)=@_;my$Unit=1/(2**$Zoom);my$relY1=$Y*$Unit;my$relY2=$relY1+$Unit;# note: $LimitY = ProjectF(degrees(atan(sinh(pi)))) = log(sinh(pi)+cosh(pi)) = pi# note: degrees(atan(sinh(pi))) = 85.051128..#my $LimitY = ProjectF(85.0511);# so stay simple and more accuratemy$LimitY=pi;my$RangeY=2*$LimitY;$relY1=$LimitY-$RangeY*$relY1;$relY2=$LimitY-$RangeY*$relY2;my$Lat1=ProjectMercToLat($relY1);my$Lat2=ProjectMercToLat($relY2);$Unit=360/(2**$Zoom);my$Long1=-180+$X*$Unit;return($Lat2,$Long1,$Lat1,$Long1+$Unit);# S,W,N,E}subProjectMercToLat($){my$MercY=shift;returnrad2deg(atan(sinh($MercY)));}subProjectF{my$Lat=shift;$Lat=deg2rad($Lat);my$Y=log(tan($Lat)+sec($Lat));return$Y;}
Lon./lat. to bbox
useMath::Trig;subgetTileNumber{my($lat,$lon,$zoom)=@_;my$xtile=int(($lon+180)/360*2**$zoom);my$ytile=int((1-log(tan(deg2rad($lat))+sec(deg2rad($lat)))/pi)/2*2**$zoom);return($xtile,$ytile);}subgetLonLat{my($xtile,$ytile,$zoom)=@_;my$n=2**$zoom;my$lon_deg=$xtile/$n*360.0-180.0;my$lat_deg=rad2deg(atan(sinh(pi*(1-2*$ytile/$n))));return($lon_deg,$lat_deg);}# convert from permalink OSM format like:# https://www.openstreetmap.org/?lat=43.731049999999996&lon=15.79375&zoom=13&layers=M# to OSM "Export" iframe embedded bbox format like:# https://www.openstreetmap.org/export/embed.html?bbox=15.7444,43.708,15.8431,43.7541&layer=mapniksubLonLat_to_bbox{my($lat,$lon,$zoom)=@_;my$width=425;my$height=350;# note: must modify this to match your embed map width/height in pixelsmy$tile_size=256;my($xtile,$ytile)=getTileNumber($lat,$lon,$zoom);my$xtile_s=($xtile*$tile_size-$width/2) /$tile_size;my$ytile_s=($ytile*$tile_size-$height/2) /$tile_size;my$xtile_e=($xtile*$tile_size+$width/2) /$tile_size;my$ytile_e=($ytile*$tile_size+$height/2) /$tile_size;my($lon_s,$lat_s)=getLonLat($xtile_s,$ytile_s,$zoom);my($lon_e,$lat_e)=getLonLat($xtile_e,$ytile_e,$zoom);my$bbox="$lon_s,$lat_s,$lon_e,$lat_e";return$bbox;}
constEARTH_CIR_METERS=40075016.686;constTILE_SIZE=256constdegreesPerMeter=360/EARTH_CIR_METERS;constLIMIT_Y=toDegrees(Math.atan(Math.sinh(Math.PI)))// around 85.0511...functiontoRadians(degrees){returndegrees*Math.PI/180;}functiontoDegrees(radians){return(radians/Math.PI)*180}functiontile2long(x,z){return(x/Math.pow(2,z)*360-180);}functionlonOnTile(lon,zoom){return((lon+180)/360)*Math.pow(2,zoom)}functiontile2lat(y,z){constn=Math.PI-2*Math.PI*y/Math.pow(2,z);return(180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n))));}functionlatOnTile(lat,zoom){return(((1-Math.log(Math.tan((lat*Math.PI)/180)+1/Math.cos((lat*Math.PI)/180))/Math.PI)/2)*Math.pow(2,zoom))}functionlatLngToBounds(lat,lng,zoom,width,height){// width and height must correspond to the iframe width/heightconstmetersPerPixelEW=EARTH_CIR_METERS/Math.pow(2,zoom+8);constshiftMetersEW=width/2*metersPerPixelEW;constshiftDegreesEW=shiftMetersEW*degreesPerMeter;constsouthTile=(TILE_SIZE*latOnTile(lat,zoom)+height/2)/TILE_SIZEconstnorthTile=(TILE_SIZE*latOnTile(lat,zoom)-height/2)/TILE_SIZEreturn{south:Math.max(tile2lat(southTile,zoom),-LIMIT_Y),west:lng-shiftDegreesEW,north:Math.min(tile2lat(northTile,zoom),LIMIT_Y),east:lng+shiftDegreesEW}}// Usage Example: create the src attribute for Open Street Map:constlatitude=47constlongitude=12constzoom=16constwidth=450constheight=350constbb=latLngToBounds(latitude,longitude,zoom,width,height);constsrc=["https://www.openstreetmap.org/export/embed.html?bbox=",bb.west,",",bb.south,",",bb.east,",",bb.north,"&layer=mapnik&marker=",latitude,",",longitude,].join('');
<xsl:transformxmlns:xsl="http://www.w3.org/1999/XSL/Transform"xmlns:m="http://exslt.org/math"extension-element-prefixes="m"version="1.0"><xsl:outputmethod="text"/><xsl:variablename="pi"select="3.14159265358979323846"/><xsl:templatename="tiley"><xsl:paramname="lat"/><xsl:paramname="zoomfact"/><xsl:variablename="a"select="($lat * $pi) div 180.0"/><xsl:variablename="b"select="m:log(m:tan($a) + (1.0 div m:cos($a)))"/><xsl:variablename="c"select="(1.0 - ($b div $pi)) div 2.0"/><xsl:value-ofselect="floor($c * $zoomfact)"/></xsl:template><xsl:templatename="tilename"><xsl:paramname="lat"/><xsl:paramname="lon"/><xsl:paramname="zoom"select="10"/><xsl:variablename="zoomfact"select="m:power(2,$zoom)"/><xsl:variablename="x"select="floor((360.0 + ($lon * 2)) * $zoomfact div 720.0)"/><xsl:variablename="y"><xsl:call-templatename="tiley"><xsl:with-paramname="lat"select="$lat"/><xsl:with-paramname="zoomfact"select="$zoomfact"/></xsl:call-template></xsl:variable><xsl:value-ofselect="concat($zoom,'/',$x,'/',$y)"/></xsl:template><xsl:templatematch="/"><xsl:call-templatename="tilename"><xsl:with-paramname="lat"select="49.867731999999997"/><xsl:with-paramname="lon"select="8.6295369999999991"/><xsl:with-paramname="zoom"select="14"/></xsl:call-template></xsl:template></xsl:transform>
function osmTileRef iLat, iLong, iZoom --> part path
local n, xTile, yTile
put (2 ^ iZoom) into n
put (iLong + 180) / 360 * n into xTile
multiply iLat by (pi / 180) -- convert to radians
put ((1 - ln(tan(iLat) + 1 / cos(iLat)) / pi) / 2) * n into yTile
return "/" & iZoom & "/" & trunc(xTile) & "/" & trunc(yTile)
end osmTileRef
function osmTileCoords xTile, yTile, iZoom --> coordinates
local twoPzoom, iLong, iLat, n
put (2 ^ iZoom) into twoPzoom
put xTile / twoPzoom * 360 - 180 into iLong
put pi - 2 * pi * yTile / twoPzoom into n
put "n1=" && n
put 180 / pi * atan(0.5 * (exp(n) - exp(-n))) into iLat
return iLat & comma & iLong
end osmTileCoords
deg2num<-function(lat_deg,lon_deg,zoom){lat_rad<-lat_deg*pi/180n<-2.0^zoomxtile<-floor((lon_deg+180.0)/360.0*n)ytile=floor((1.0-log(tan(lat_rad)+(1/cos(lat_rad)))/pi)/2.0*n)return(c(xtile,ytile))# return(paste(paste("https://tile.openstreetmap.org", zoom, xtile, ytile, sep="/"),".png",sep=""))}# Returns data frame containing detailed info for all zoomsdeg2num.all<-function(lat_deg,lon_deg){nums<-as.data.frame(matrix(ncol=6,nrow=21))colnames(nums)<-c('zoom','x','y','mapquest_osm','mapquest_aerial','osm')rownames(nums)<-0:20for (zoomin0:20){num<-deg2num(lat_deg,lon_deg,zoom)nums[1+zoom,'zoom']<-zoomnums[1+zoom,'x']<-num[1]nums[1+zoom,'y']<-num[2]nums[1+zoom,'mapquest_osm']<-paste('http://otile1.mqcdn.com/tiles/1.0.0/map/',zoom,'/',num[1],'/',num[2],'.jpg',sep='')nums[1+zoom,'mapquest_aerial']<-paste('http://otile1.mqcdn.com/tiles/1.0.0/sat/',zoom,'/',num[1],'/',num[2],'.jpg',sep='')nums[1+zoom,'osm']<-paste('https://tile.openstreetmap.org/',zoom,'/',num[1],'/',num[2],'.png',sep='')}return(nums)}
Tile numbers to lat./lon. / Coordinates to tile numbers / Sample of usage, with optional tms-format support
xtile2long(){xtile=$1zoom=$2echo"${xtile}${zoom}"|awk'{printf("%.9f", $1 / 2.0^$2 * 360.0 - 180)}'}
long2xtile(){long=$1zoom=$2echo"${long}${zoom}"|awk'{ xtile = ($1 + 180.0) / 360 * 2.0^$2; xtile+=xtile<0?-0.5:0.5; printf("%d", xtile ) }'}
ytile2lat(){ytile=$1;zoom=$2;tms=$3;if[!-z"${tms}"]then# from tms_numbering into osm_numberingytile=`echo"${ytile}"${zoom}|awk'{printf("%d\n",((2.0^$2)-1)-$1)}'`;filat=`echo"${ytile}${zoom}"|awk-vPI=3.14159265358979323846'{ num_tiles = PI - 2.0 * PI * $1 / 2.0^$2; printf("%.9f", 180.0 / PI * atan2(0.5 * (exp(num_tiles) - exp(-num_tiles)),1)); }'`;echo"${lat}";}
lat2ytile(){lat=$1;zoom=$2;tms=$3;ytile=`echo"${lat}${zoom}"|awk-vPI=3.14159265358979323846'{ tan_x=sin($1 * PI / 180.0)/cos($1 * PI / 180.0); ytile = (1 - log(tan_x + 1/cos($1 * PI/ 180))/PI)/2 * 2.0^$2; ytile+=ytile<0?-0.5:0.5; printf("%d", ytile ) }'`;if[!-z"${tms}"]then# from oms_numbering into tms_numberingytile=`echo"${ytile}"${zoom}|awk'{printf("%d\n",((2.0^$2)-1)-$1)}'`;fiecho"${ytile}";}# ------------------------------------# Sample of use: # Position Brandenburg Gate, Berlin# ------------------------------------LONG=13.37771496361961;LAT=52.51628011262304;ZOOM=17;TILE_X=70406;TILE_Y=42987;TILE_Y_TMS=88084;TMS="";# when NOT empty: tms format assumed# ------------------------------------# assume input/output of y is in oms-format:LONG=$(xtile2long${TILE_X}${ZOOM});LAT=$(ytile2lat${TILE_Y}${ZOOM}${TMS});# Result should be longitude[13.375854492] latitude[52.517892228]TILE_X=$(long2xtile${LONG}${ZOOM});TILE_Y=$(lat2ytile${LAT}${ZOOM}${TMS});# Result should be x[70406] y_oms[42987] # ------------------------------------# assume input/output of y is in tms-format:TMS="tms";TILE_Y_TMS=$(lat2ytile${LAT}${ZOOM}${TMS});LAT_TMS=$(ytile2lat${TILE_Y_TMS}${ZOOM}${TMS});echo"Result should be y_oms[${TILE_Y}] latitude[${LAT}] ; y_tms[${TILE_Y_TMS}] latitude_tms[${LAT_TMS}] "# latitude and latitude_tms should have the same value ; y_oms and y_tms should have the given start values:# Result should be y_oms[42987] latitude[52.517892228] ; y_tms[88084] latitude_tms[52.517892228]# ------------------------------------
Tile bounding box and center
n=$(ytile2lat`expr${TILE_Y}`${ZOOM})s=$(ytile2lat`expr${TILE_Y}+1`${ZOOM})e=$(xtile2long`expr${TILE_X}+1`${ZOOM})w=$(xtile2long`expr${TILE_X}`${ZOOM})echo"bbox=$w,$s,$e,$n"echo"-I-> Result should be [bbox=13.375854492,52.516220864,13.378601074,52.517892228]";center_lat=`echo"$s$n"|awk'{printf("%.8f", ($1 + $2) / 2.0)}'`center_lon=`echo"$w$e"|awk'{printf("%.8f", ($1 + $2) / 2.0)}'`echo"center=$center_lat,$center_lon"echo"-I-> Result should be [center=52.51705655,13.37722778]";
(note: Slippy tiles and Google map tiles count tile 0,0 down from the top-left of the tile grid; the TMS spec specifies tiles count up from 0,0 in the lower-left!)