使用循环计算缩放级别非常幼稚。使用数学方法更好。
下面是函数(返回类型:浮点数)
public static double calcZoom(int visible_distance, int img_width)
{
visible_distance = Math.abs(visible_distance);
double equator_length = 40075016;
double zoom256 = Math.log(equator_length/visible_distance)/Math.log(2);
int x = (int) (Math.log(img_width/256)/Math.log(2));
double zoom = zoom256 + x;
return zoom;
}
示例调用:
public static void main(String[] args)
{
double zoom = MainClass.calcZoom(1000, 256);
System.out.println("zoom: " + String.valueOf(zoom));
return;
}
计算缩放级别的数学公式为:
equator_length = 40075016
zoom_level = logE(equator_length/distance)/logE(2) + logE(img_width/256)/logE(2)
// The zoom_level computed here is a float number.
就这些啦,朋友们!:-)
注意:上面的解决方案只适用于赤道附近的缩放级别。 如果您想要一个适用于所有纬度的解决方案,您需要知道所需缩放级别上同一纬度的平行线长度。 calcZoom
方法应更改为
private double calcZoom(int visible_distance, int img_width, double atLatitude) {
double parallel_length = this.calcParallelLegth(atLatitude);
zoom256 = Math.log(parallel_length/visible_distance))/Math.log(2)
x = (int) Math.log(img_width/256)/Math.log(2)
zoom = zoom256 + x
return zoom;
}
this.calcParallelLegth(atLatitude)
返回在纬度atLatitude
处的平行线长度。
您可以使用某些库(最好使用Vincenty公式)自己计算长度。
或者
如果您没有这样的库(或者您不想搜索库,或者您只是想要一个完整的代码),在此答案底部您可以找到整个可工作代码,其中包含使用通过Vincenty公式计算的表格的所有纬度处的平行线长度,并且具有3%的容差。
注意:
仅当您想了解公式(或者检查公式是否正确)时才需要阅读下面内容
以下是公式解释:
简单来说!
让我们将问题分为两部分。
第一部分
计算256x256大小图像的缩放级别
第二部分
适应具有不同大小的图像的缩放级别
解决第一部分
图像大小为256x256。
缩放级别0显示整个赤道。
每个后续缩放级别让我看到之前的一半。
赤道长为40,075,016米(根据WGS-84 (*1) 和
Vincenty公式 (*2))
zoom=0 -> 40,075,016 / 1 = 40,075,016 meters visible Note: 2^0=1
zoom=1 -> 40,075,016 / 2 = 20,037,508 meters visible Note: 2^1=2
zoom=2 -> 40,075,016 / 4 = 10,018,754 meters visible Note: 2^2=4
zoom=3 -> 40,075,016 / 8 = 5,009,377 meters visible Note: 2^3=8
zoom=4 -> 40,075,016 / 16 = 2,504,688.5 meters visible Note: 2^4=16
zoom=5 -> 40,075,016 / 2^5 = 1,252,344.25 meters visible Note= 2^5=32
zoom=6 -> 40,075,016 / 2^6 = 636,172.125 meters visible Note= 2^6=64
...
zoom -> equator_length / 2^zoom = visible_distance
如上所示,每个后续的缩放级别让我看到比之前少一半。
zoom是所需的缩放级别。
visible_distance是图像水平显示的米数。
如果你想要1公里,那么你需要使用visible_distance=1000计算zoom
让我们来找出缩放公式。
这就是数学发挥作用的地方(“无聊”的魔法 stuff)。
equator_length / 2^zoom = visible_distance ->
-> equator_length / visible_distance = 2^zoom ->
-> log2(equator_length / visible_distance) = log2(2^zoom) -> (*3)
-> log2(equator_length / visible_distance) = zoom*log2(2) -> (*4)
-> log2(equator_length / visible_distance) = zoom*1 -> (*5)
-> log2(equator_length / visible_distance) = zoom ->
-> logE(equator_length / visible_distance)/logE(2) = zoom -> (*6)
一张256x256图像的缩放级别公式如下:
zoom256 = logE(equator_length/visible_distance) / logE(2)
第二部分解决!
将缩放调整为所需的图像大小。
每当图像宽度加倍时,查看整个赤道所需的缩放增加一倍。
例如:
在512x512图像中,查看整个赤道所需的缩放级别为1。
在1024x1024图像中,查看整个赤道所需的缩放级别为2。
在2048x2048图像中,查看整个赤道所需的缩放级别为3。
也就是说
width= 256 -> 256/256 = 1 -> zoom=0 (needed to see the whole equator)
width= 512 -> 512/256 = 2 -> zoom=1 (needed to see the whole equator)
width=1024 -> 1024/256 = 4 -> zoom=2 (needed to see the whole equator)
width=2048 -> 2048/256 = 8 -> zoom=3 (needed to see the whole equator)
width=4096 -> 4096/256 = 2^4 -> zoom=4 (needed to see the whole equator)
width=4096 -> 4096/256 = 2^5 -> zoom=5 (needed to see the whole equator)
...宽度 -> 宽度/256 = 2^x -> 缩放= x(需要看到整个赤道)
这意味着(缩放级别为
- with an 512x512 image, the zoom needed is zoom256+1
- with an 1024x1024 image, the zoom needed is zoom256+2
- with an 2048x2048 image, the zoom needed is zoom256+3
...
- with an WIDTHxHEIGHT image, the zoom needed is zoom256+x
我们需要适应缩放到所需的图像大小
x。
因此,从中提取x是一个问题。
width/256 = 2^x
让我们来做这件事吧。
width/256 = 2^x ->
-> log2(width/256) = log2(2^x) -> (*3)
-> log2(width/256) = x * log2(2) -> (*4)
-> log2(width/256) = x * 1 -> (*5)
-> log2(width/256) = x ->
-> logE(width/256) / logE(2) = x -> (*6)
现在我们有了
x公式。
对于一张宽度为WIDTH,高度为HEIGHT的图片,缩放级别公式如下:
zoom = zoom256 + x
所以,如果你想在一张512x512像素的图片中让1公里范围内的内容可以被看到,那么...
zoom256 = logE(40075016/1000) / logE(2) = 15.29041547592718
x = logE(512/256) / logE(2) = 1
zoom = zoom256 + z = 15.29041547592718 + 1 = 16.29041547592718
如果必须为整数
zoom = floor(zoom) = 16
完成!
(*3) expr1=expr2 <-> log(expr1)=log(expr2)
(*4) logN(a^b) = b * logN(a)
(*5) logN(N) = 1
(*6) logN(expr) = log(expr)/log(N)
(*7) log(a/b) = log(a) - log(b)
这里是完整的代码,它计算每个纬度下的缩放级别和图像宽度。
class MainClass
{
public static int getParallelLength(double atLatitude)
{
int FR_LAT = 0;
int TO_LAT = 1;
int PA_LEN = 2;
int PC_ERR = 3;
double tbl[][] = {
{ 0.00, 12.656250000000000, 40075016, 2.410},
{12.66, 17.402343750000000, 39107539, 2.180},
{17.40, 22.148437500000000, 38252117, 2.910},
{22.15, 25.708007812500000, 37135495, 2.700},
{25.71, 28.377685546875000, 36130924, 2.330},
{28.38, 31.047363281250000, 35285940, 2.610},
{31.05, 33.717041015625000, 34364413, 2.890},
{33.72, 35.719299316406250, 33368262, 2.380},
{35.72, 37.721557617187500, 32573423, 2.560},
{37.72, 39.723815917968750, 31738714, 2.750},
{39.72, 41.726074218750000, 30865121, 2.950},
{41.73, 43.227767944335938, 29953681, 2.360},
{43.23, 44.729461669921875, 29245913, 2.480},
{44.73, 46.231155395507812, 28517939, 2.620},
{46.23, 47.732849121093750, 27770248, 2.760},
{47.73, 49.234542846679688, 27003344, 2.900},
{49.23, 50.360813140869141, 26217745, 2.290},
{50.36, 51.487083435058594, 25616595, 2.380},
{51.49, 52.613353729248047, 25005457, 2.480},
{52.61, 53.739624023437500, 24384564, 2.580},
{53.74, 54.865894317626953, 23754152, 2.690},
{54.87, 55.992164611816406, 23114464, 2.800},
{55.99, 57.118434906005859, 22465745, 2.920},
{57.12, 57.963137626647949, 21808245, 2.280},
{57.96, 58.807840347290039, 21309508, 2.360},
{58.81, 59.652543067932129, 20806081, 2.440},
{59.65, 60.497245788574219, 20298074, 2.520},
{60.50, 61.341948509216309, 19785597, 2.610},
{61.34, 62.186651229858398, 19268762, 2.700},
{62.19, 63.031353950500488, 18747680, 2.800},
{63.03, 63.876056671142578, 18222465, 2.900},
{63.88, 64.509583711624146, 17693232, 2.250},
{64.51, 65.143110752105713, 17293739, 2.320},
{65.14, 65.776637792587280, 16892100, 2.390},
{65.78, 66.410164833068848, 16488364, 2.460},
{66.41, 67.043691873550415, 16082582, 2.530},
{67.04, 67.677218914031982, 15674801, 2.610},
{67.68, 68.310745954513550, 15265074, 2.690},
{68.31, 68.944272994995117, 14853450, 2.780},
{68.94, 69.577800035476685, 14439980, 2.870},
{69.58, 70.211327075958252, 14024715, 2.970},
{70.21, 70.686472356319427, 13607707, 2.300},
{70.69, 71.161617636680603, 13293838, 2.360},
{71.16, 71.636762917041779, 12979039, 2.430},
{71.64, 72.111908197402954, 12663331, 2.500},
{72.11, 72.587053477764130, 12346738, 2.570},
{72.59, 73.062198758125305, 12029281, 2.640},
{73.06, 73.537344038486481, 11710981, 2.720},
{73.54, 74.012489318847656, 11391862, 2.800},
{74.01, 74.487634599208832, 11071946, 2.890},
{74.49, 74.962779879570007, 10751254, 2.980},
{74.96, 75.319138839840889, 10429810, 2.310},
{75.32, 75.675497800111771, 10188246, 2.370},
{75.68, 76.031856760382652, 9946280, 2.430},
{76.03, 76.388215720653534, 9703923, 2.500},
{76.39, 76.744574680924416, 9461183, 2.560},
{76.74, 77.100933641195297, 9218071, 2.640},
{77.10, 77.457292601466179, 8974595, 2.710},
{77.46, 77.813651561737061, 8730766, 2.790},
{77.81, 78.170010522007942, 8486593, 2.880},
{78.17, 78.526369482278824, 8242085, 2.970},
{78.53, 78.793638702481985, 7997252, 2.290},
{78.79, 79.060907922685146, 7813420, 2.350},
{79.06, 79.328177142888308, 7629414, 2.410},
{79.33, 79.595446363091469, 7445240, 2.470},
{79.60, 79.862715583294630, 7260900, 2.540},
{79.86, 80.129984803497791, 7076399, 2.600},
{80.13, 80.397254023700953, 6891742, 2.680},
{80.40, 80.664523243904114, 6706931, 2.750},
{80.66, 80.931792464107275, 6521972, 2.830},
{80.93, 81.199061684310436, 6336868, 2.920},
{81.20, 81.399513599462807, 6151624, 2.250},
{81.40, 81.599965514615178, 6012600, 2.310},
{81.60, 81.800417429767549, 5873502, 2.360},
{81.80, 82.000869344919920, 5734331, 2.420},
{82.00, 82.201321260072291, 5595088, 2.480},
{82.20, 82.401773175224662, 5455775, 2.550},
{82.40, 82.602225090377033, 5316394, 2.620},
{82.60, 82.802677005529404, 5176947, 2.690},
{82.80, 83.003128920681775, 5037435, 2.770},
{83.00, 83.203580835834146, 4897860, 2.850},
{83.20, 83.404032750986516, 4758224, 2.930},
{83.40, 83.554371687350795, 4618528, 2.260},
{83.55, 83.704710623715073, 4513719, 2.320},
{83.70, 83.855049560079351, 4408878, 2.370},
{83.86, 84.005388496443629, 4304006, 2.430},
{84.01, 84.155727432807907, 4199104, 2.490},
{84.16, 84.306066369172186, 4094172, 2.560},
{84.31, 84.456405305536464, 3989211, 2.630},
{84.46, 84.606744241900742, 3884223, 2.700},
{84.61, 84.757083178265020, 3779207, 2.770},
{84.76, 84.907422114629298, 3674165, 2.850},
{84.91, 85.057761050993577, 3569096, 2.940},
{85.06, 85.170515253266785, 3464003, 2.270},
{85.17, 85.283269455539994, 3385167, 2.320},
{85.28, 85.396023657813203, 3306318, 2.380},
{85.40, 85.508777860086411, 3227456, 2.440},
{85.51, 85.621532062359620, 3148581, 2.500},
{85.62, 85.734286264632829, 3069693, 2.570},
{85.73, 85.847040466906037, 2990793, 2.630},
{85.85, 85.959794669179246, 2911882, 2.710},
{85.96, 86.072548871452454, 2832959, 2.780},
{86.07, 86.185303073725663, 2754025, 2.860},
{86.19, 86.298057275998872, 2675080, 2.950},
{86.30, 86.382622927703778, 2596124, 2.280},
{86.38, 86.467188579408685, 2536901, 2.330},
{86.47, 86.551754231113591, 2477672, 2.390},
{86.55, 86.636319882818498, 2418437, 2.440},
{86.64, 86.720885534523404, 2359197, 2.510},
{86.72, 86.805451186228311, 2299952, 2.570},
{86.81, 86.890016837933217, 2240701, 2.640},
{86.89, 86.974582489638124, 2181446, 2.710},
{86.97, 87.059148141343030, 2122186, 2.790},
{87.06, 87.143713793047937, 2062921, 2.870},
{87.14, 87.228279444752843, 2003652, 2.950},
{87.23, 87.291703683531523, 1944378, 2.280},
{87.29, 87.355127922310203, 1899919, 2.340},
{87.36, 87.418552161088883, 1855459, 2.390},
{87.42, 87.481976399867563, 1810996, 2.450},
{87.48, 87.545400638646242, 1766531, 2.510},
{87.55, 87.608824877424922, 1722063, 2.580},
{87.61, 87.672249116203602, 1677594, 2.650},
{87.67, 87.735673354982282, 1633122, 2.720},
{87.74, 87.799097593760962, 1588648, 2.790},
{87.80, 87.862521832539642, 1544172, 2.880},
{87.86, 87.925946071318322, 1499695, 2.960},
{87.93, 87.973514250402332, 1455215, 2.290},
{87.97, 88.021082429486341, 1421854, 2.340},
{88.02, 88.068650608570351, 1388493, 2.400},
{88.07, 88.116218787654361, 1355130, 2.460},
{88.12, 88.163786966738371, 1321766, 2.520},
{88.16, 88.211355145822381, 1288401, 2.580},
{88.21, 88.258923324906391, 1255036, 2.650},
{88.26, 88.306491503990401, 1221669, 2.730},
{88.31, 88.354059683074411, 1188302, 2.800},
{88.35, 88.401627862158421, 1154934, 2.880},
{88.40, 88.449196041242431, 1121565, 2.970},
{88.45, 88.484872175555438, 1088195, 2.290},
{88.48, 88.520548309868445, 1063167, 2.350},
{88.52, 88.556224444181453, 1038139, 2.410},
{88.56, 88.591900578494460, 1013110, 2.470},
{88.59, 88.627576712807468, 988081, 2.530},
{88.63, 88.663252847120475, 963052, 2.590},
{88.66, 88.698928981433482, 938022, 2.660},
{88.70, 88.734605115746490, 912992, 2.740},
{88.73, 88.770281250059497, 887961, 2.810},
{88.77, 88.805957384372505, 862930, 2.900},
{88.81, 88.841633518685512, 837899, 2.980},
{88.84, 88.868390619420268, 812867, 2.300},
{88.87, 88.895147720155023, 794093, 2.360},
{88.90, 88.921904820889779, 775319, 2.420},
{88.92, 88.948661921624534, 756545, 2.480},
{88.95, 88.975419022359290, 737771, 2.540},
{88.98, 89.002176123094046, 718996, 2.610},
{89.00, 89.028933223828801, 700221, 2.680},
{89.03, 89.055690324563557, 681446, 2.750},
{89.06, 89.082447425298312, 662671, 2.830},
{89.08, 89.109204526033068, 643896, 2.910},
{89.11, 89.129272351584135, 625121, 2.250},
{89.13, 89.149340177135201, 611039, 2.300},
{89.15, 89.169408002686268, 596957, 2.350},
{89.17, 89.189475828237335, 582876, 2.410},
{89.19, 89.209543653788401, 568794, 2.470},
{89.21, 89.229611479339468, 554712, 2.530},
{89.23, 89.249679304890535, 540630, 2.600},
{89.25, 89.269747130441601, 526548, 2.670},
{89.27, 89.289814955992668, 512466, 2.740},
{89.29, 89.309882781543735, 498384, 2.820},
{89.31, 89.329950607094801, 484302, 2.900},
{89.33, 89.350018432645868, 470219, 2.990},
{89.35, 89.365069301809172, 456137, 2.310},
{89.37, 89.380120170972475, 445575, 2.370},
{89.38, 89.395171040135779, 435013, 2.420},
{89.40, 89.410221909299082, 424451, 2.480},
{89.41, 89.425272778462386, 413889, 2.550},
{89.43, 89.440323647625689, 403328, 2.610},
{89.44, 89.455374516788993, 392766, 2.680},
{89.46, 89.470425385952296, 382204, 2.760},
{89.47, 89.485476255115600, 371642, 2.840},
{89.49, 89.500527124278904, 361080, 2.920},
{89.50, 89.511815276151381, 350518, 2.260},
{89.51, 89.523103428023859, 342596, 2.310},
{89.52, 89.534391579896337, 334674, 2.360},
{89.53, 89.545679731768814, 326753, 2.420},
{89.55, 89.556967883641292, 318831, 2.480},
{89.56, 89.568256035513770, 310910, 2.540},
{89.57, 89.579544187386247, 302988, 2.610},
{89.58, 89.590832339258725, 295066, 2.680},
{89.59, 89.602120491131203, 287145, 2.750},
{89.60, 89.613408643003680, 279223, 2.830},
{89.61, 89.624696794876158, 271301, 2.910},
{89.62, 89.633162908780520, 263380, 2.250},
{89.63, 89.641629022684882, 257438, 2.300},
{89.64, 89.650095136589243, 251497, 2.360},
{89.65, 89.658561250493605, 245556, 2.410},
{89.66, 89.667027364397967, 239615, 2.470},
{89.67, 89.675493478302329, 233673, 2.540},
{89.68, 89.683959592206691, 227732, 2.600},
{89.68, 89.692425706111052, 221791, 2.670},
{89.69, 89.700891820015414, 215849, 2.750},
{89.70, 89.709357933919776, 209908, 2.830},
{89.71, 89.717824047824138, 203967, 2.910},
{89.72, 89.724173633252406, 198026, 2.250},
{89.72, 89.730523218680673, 193570, 2.300},
{89.73, 89.736872804108941, 189114, 2.350},
{89.74, 89.743222389537209, 184658, 2.410},
{89.74, 89.749571974965477, 180202, 2.470},
{89.75, 89.755921560393745, 175746, 2.530},
{89.76, 89.762271145822012, 171290, 2.600},
{89.76, 89.768620731250280, 166834, 2.670},
{89.77, 89.774970316678548, 162378, 2.740},
{89.77, 89.781319902106816, 157922, 2.820},
{89.78, 89.787669487535084, 153466, 2.900},
{89.79, 89.794019072963351, 149010, 2.990},
{89.79, 89.798781262034552, 144554, 2.310},
{89.80, 89.803543451105753, 141212, 2.360},
{89.80, 89.808305640176954, 137869, 2.420},
{89.81, 89.813067829248155, 134527, 2.480},
{89.81, 89.817830018319356, 131185, 2.540},
{89.82, 89.822592207390556, 127843, 2.610},
{89.82, 89.827354396461757, 124501, 2.680},
{89.83, 89.832116585532958, 121159, 2.750},
{89.83, 89.836878774604159, 117817, 2.830},
{89.84, 89.841640963675360, 114475, 2.910},
{89.84, 89.845212605478764, 111133, 2.250},
{89.85, 89.848784247282168, 108627, 2.300},
{89.85, 89.852355889085572, 106120, 2.360},
{89.85, 89.855927530888977, 103614, 2.410},
{89.86, 89.859499172692381, 101107, 2.470},
{89.86, 89.863070814495785, 98601, 2.540},
{89.86, 89.866642456299189, 96094, 2.600},
{89.87, 89.870214098102593, 93588, 2.670},
{89.87, 89.873785739905998, 91081, 2.750},
{89.87, 89.877357381709402, 88575, 2.830},
{89.88, 89.880929023512806, 86068, 2.910},
{89.88, 89.883607754865352, 83562, 2.240},
{89.88, 89.886286486217898, 81682, 2.300},
{89.89, 89.888965217570444, 79802, 2.350},
{89.89, 89.891643948922990, 77922, 2.410},
{89.89, 89.894322680275536, 76042, 2.470},
{89.89, 89.897001411628082, 74162, 2.530},
{89.90, 89.899680142980628, 72282, 2.600},
{89.90, 89.902358874333174, 70402, 2.660},
{89.90, 89.905037605685720, 68523, 2.740},
{89.91, 89.907716337038266, 66643, 2.820},
{89.91, 89.910395068390812, 64763, 2.900},
{89.91, 89.913073799743358, 62883, 2.980},
{89.91, 89.915082848257768, 61003, 2.310},
{89.92, 89.917091896772178, 59593, 2.360},
{89.92, 89.919100945286587, 58183, 2.420},
{89.92, 89.921109993800997, 56773, 2.480},
{89.92, 89.923119042315406, 55363, 2.540},
{89.92, 89.925128090829816, 53953, 2.610},
{89.93, 89.927137139344225, 52543, 2.680},
{89.93, 89.929146187858635, 51134, 2.750},
{89.93, 89.931155236373044, 49724, 2.830},
{89.93, 89.933164284887454, 48314, 2.910},
{89.93, 89.934671071273257, 46904, 2.250},
{89.93, 89.936177857659061, 45846, 2.300},
{89.94, 89.937684644044865, 44789, 2.360},
{89.94, 89.939191430430668, 43731, 2.410},
{89.94, 89.940698216816472, 42674, 2.470},
{89.94, 89.942205003202275, 41617, 2.540},
{89.94, 89.943711789588079, 40559, 2.600},
{89.94, 89.945218575973882, 39502, 2.670},
{89.95, 89.946725362359686, 38444, 2.740},
{89.95, 89.948232148745490, 37387, 2.820},
{89.95, 89.949738935131293, 36329, 2.900}
};
for(int r=0; r < tbl.length; r++)
{
double fromLat = tbl[r][FR_LAT];
double toLat = tbl[r][TO_LAT];
double atLat = atLatitude;
if(fromLat <= atLat && atLat < toLat)
{
double parallelLength = tbl[r][PA_LEN];
return (int)parallelLength;
}
}
return 0;
}
public static double calcZoom(int visible_distance, int img_width, double atLat)
{
visible_distance = Math.abs(visible_distance);
double parallel_length = MainClass.getParallelLength(atLat);
double zoom256 = Math.log(parallel_length/visible_distance)/Math.log(2);
int x = (int) (Math.log(img_width/256)/Math.log(2));
double zoom = zoom256 + x;
return zoom;
}
public static void main(String[] args)
{
int len;
double zoom;
len = MainClass.getParallelLength(0);
System.out.println("parallel length at 0: " + String.valueOf(len));
len = MainClass.getParallelLength(89.9);
System.out.println("parallel length at 89.9: " + String.valueOf(len));
zoom = MainClass.calcZoom(100000, 256, 0);
System.out.println("zoom (100km, width:256, lat:0): " + String.valueOf(zoom));
zoom = MainClass.calcZoom(100000, 512, 0);
System.out.println("zoom (100km, width:512, lat:0): " + String.valueOf(zoom));
zoom = MainClass.calcZoom(100000, 256, 60);
System.out.println("zoom (100km, width:256, lat:60): " + String.valueOf(zoom));
return;
}
}