首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何正确缩放给定的坐标以适应视图的边界而不失真?

如何正确缩放给定的坐标以适应视图的边界而不失真?
EN

Stack Overflow用户
提问于 2018-06-03 02:32:23
回答 2查看 908关注 0票数 1

我有一个纬度/经度对列表,希望将它们描述为连接线的路径绘制到我的自定义视图中,但要使用正确的比率。

到目前为止,我的解决方案是这样的:找到纬度和经度的最小值和最大值,将每个值描述为一个介于0和1之间的数字,然后将它们乘以我的视图的高度/宽度。因此,我的道路总是延伸到我的视野的边界。

例如,如果我从北到南走10000米,在这段时间里只向西走1米,然后向东走2米,我的路径看起来就像这样(向四面八方延伸):

代码语言:javascript
复制
---------------
|      *      |
|  ****       |
|**           |
| *           |
|  ***        |
|     ****    |
|         **  |
|           **|
---------------

但我希望它看起来像这样:

代码语言:javascript
复制
---------------
|      *      |
|      *      |
|     *       |
|     **      |
|       *     |
|       *     |
|       *     |
|       *     |
---------------

因此,当我主要从北向南行走时,路线应该占满我视图的整个高度,x位置应该相应地显示出来。当我大部分时间是从西向东走的时候,它应该占据整个宽度。

不知何故,我不知道如何正确缩放我的值,以便在我的视图中绘制它们。我希望你能理解我的问题,并能帮助我解决它。提前感谢!:)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-06-03 04:12:29

假设你有以下变量,希望它们的含义很清楚:screenWidthscreenHeightminLonmaxLonminLatmaxLat。您需要的是将lonlat映射到屏幕坐标xy,这样宽度或高度都会被填充,但圆仍然是圆(距离的水平和垂直比例相同)。

经度差和纬度差的距离之比几乎就是纬度的余弦。“几乎”只是因为地球不是一个完美的球体。在纬度0°处余弦是1,因此,例如,在赤道,相同的经度和纬度差对应于相同的距离。对于“足够”小区域的地图,可以使用平均纬度来计算比率。

如果只有一个水平约束,则必须使x==0对应于minLon,使x==screenWidth-1对应于maxLon。它的线性变换(即映射)将是:

代码语言:javascript
复制
x = lon * lonScale + x0;

使用

代码语言:javascript
复制
deltaLon = maxLon - minLon;
lonScale = (screenWidth - 1) / deltaLon;
x0 = - minLon * lonScale;

同样,如果您只有一个垂直约束:

代码语言:javascript
复制
y = y0 - lat * latScale; // i.e.: lat * (-latScale) + y0

使用

代码语言:javascript
复制
deltaLat = maxLat - minLat;
latScale = (screenHeight - 1) / deltaLat;
y0 = maxLat * latScale;

(减号是因为屏幕坐标的原点在左上角。)

现在,如果是deltaLon == 0.0deltaLat == 0.0,您不想除以0,只希望将有意义的映射应用于您正在处理的直线。如果两者都是!= 0.0,则需要在latScalelonScale之间选择较小的一个,记住它们的比率是平均纬度的余弦:

代码语言:javascript
复制
lonScale == latScale * Math.cos((maxLat + minLat) / 2.0)

所以:

代码语言:javascript
复制
avgLat = (maxLat + minLat) / 2.0;
cosFactor = Math.cos(avgLat);
if (deltaLon != 0.0 && deltaLat != 0.0) {
    if (lonScale > latScale * cosFactor) {
        lonScale = latScale * cosFactor;
        x0 = ((screenWidth - 1) - (minLon + maxLon) * lonScale) / 2.0;
    } else {
        latScale = lonScale / cosFactor;
        y0 = ((screenHeight - 1) + (minLat + maxLat) * latScale) / 2.0;
    }
}

其中,x0y0已通过求解将(maxL* - minL*) / 2.0置于屏幕中间的方程式进行了调整(*onat)。

编辑

根据您的评论,您不使用实际的经度和纬度值,而是简单地使用从东到西和从南到北方向的距离。这有点像在赤道上,余弦因子变成1。我将继续将输入坐标称为lonlat,但它们可以用任何长度单位表示,只要它们是相同的单位。

这样计算就变成了:

代码语言:javascript
复制
deltaLon = maxLon - minLon;
deltaLat = maxLat - minLat;
if (deltaLon != 0.0 && deltaLat != 0.0) {
    lonScale = (screenWidth - 1) / deltaLon;
    latScale = (screenHeight - 1) / deltaLat;
    x0 = - minLon * lonScale;
    y0 = maxLat * latScale;
    if (lonScale > latScale) {
        lonScale = latScale;
        x0 = ((screenWidth - 1) - (minLon + maxLon) * lonScale) / 2.0;
    } else {
        latScale = lonScale;
        y0 = ((screenHeight - 1) + (minLat + maxLat) * latScale) / 2.0;
    }
} else if (deltaLon != 0.0) {
    lonScale = (screenWidth - 1) / deltaLon;
    latScale = 0;
    x0 = - minLon * lonScale;
    y0 = (screenHeight - 1) / 2.0;
} else if (deltaLat != 0.0) {
    lonScale = 0;
    latScale = (screenHeight - 1) / deltaLat;
    x0 = (screenWidth - 1) / 2.0;
    y0 = maxLat * latScale;
} else {
    lonScale = 0;
    latScale = 0;
    x0 = (screenHeight - 1) / 2.0;
    y0 = (screenWidth - 1) / 2.0;
}

并且屏幕值的计算方式与一般情况完全相同,即:

代码语言:javascript
复制
x = x0 + lon * lonScale;
y = y0 - lat * latScale;
票数 3
EN

Stack Overflow用户

发布于 2018-06-03 02:43:28

我会定义一个最大纵横比。例如:

代码语言:javascript
复制
min_aspect_ratio = 5; // Minimum aspect ratio of 5:1
x_scale = screen_width/max_x_diff;
y_scale = screen_height/max_y_diff;

if(x_scale>y_scale)
    if (x_scale/y_scale < min_aspect_ratio)
        y_scale = x_scale/min_aspect_ratio;
else
    if (y_scale/x_scale < min_aspect_ratio)
        x_scale = y_scale/min_aspect_ratio;

免责声明:我没有测试这段代码。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50659975

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档