将经度/纬度转换为 X/Y 坐标

2023-12-25

我使用 Google Maps API 创建了一张地图,突出显示了明尼苏达州的所有县。基本上,我使用一组经度/纬度坐标创建了县多边形。这是生成的地图的屏幕截图:-

用户要求之一是能够拥有与图像类似的地图,以便他们可以将其嵌入到 PowerPoint/主题幻灯片中。我找不到任何有用的 Google Maps API 可以让我按原样保存自定义地图(如果您知道一种方法,请告诉我),所以我想我应该用 Java 中的 Graphics2D 来绘制它。

在阅读了将经度/纬度转换为 X/Y 坐标的公式后,我最终得到以下代码:-

private static final int    EARTH_RADIUS    = 6371;
private static final double FOCAL_LENGTH    = 500;

...

BufferedImage bi = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bi.createGraphics();

for (Coordinate coordinate : coordinates) {
    double latitude = Double.valueOf(coordinate.getLatitude());
    double longitude = Double.valueOf(coordinate.getLongitude());

    latitude = latitude * Math.PI / 180;
    longitude = longitude * Math.PI / 180;

    double x = EARTH_RADIUS * Math.sin(latitude) * Math.cos(longitude);
    double y = EARTH_RADIUS * Math.sin(latitude) * Math.sin(longitude);
    double z = EARTH_RADIUS * Math.cos(latitude);

    double projectedX = x * FOCAL_LENGTH / (FOCAL_LENGTH + z);
    double projectedY = y * FOCAL_LENGTH / (FOCAL_LENGTH + z);

    // scale the map bigger
    int magnifiedX = (int) Math.round(projectedX * 5);
    int magnifiedY = (int) Math.round(projectedY * 5);

    ...
    g.drawPolygon(...);
    ...
}

生成的地图与 Google Maps API 使用相同的经度/纬度集生成的地图类似。然而,它看起来有点倾斜,看起来有点不对劲,我不知道如何解决这个问题。

如何使县的形状看起来像上面 Google Maps API 生成的形状?

非常感谢。

最终解决方案

感谢@QuantumMechanic 和@Anon,我终于找到了解决方案。

墨卡托投影在这里确实发挥了作用。我在用着Java 地图投影库 http://sourceforge.net/projects/jmapprojlib/执行墨卡托投影的计算。

private static final int    IMAGE_WIDTH     = 1000;
private static final int    IMAGE_HEIGHT    = 1000;
private static final int    IMAGE_PADDING   = 50;

...

private List<Point2D.Double> convertToXY(List<Coordinate> coordinates) {
    List<Point2D.Double> xys = new ArrayList<Point2D.Double>();

    MercatorProjection projection = new MercatorProjection();

    for (Coordinate coordinate : coordinates) {
        double latitude = Double.valueOf(coordinate.getLatitude());
        double longitude = Double.valueOf(coordinate.getLongitude());

        // convert to radian
        latitude = latitude * Math.PI / 180;
        longitude = longitude * Math.PI / 180;

        Point2D.Double d = projection.project(longitude, latitude, new Point2D.Double());

        // shift by 10 to remove negative Xs and Ys
        // scaling by 6000 to make the map bigger
        int magnifiedX = (int) Math.round((10 + d.x) * 6000);
        int magnifiedY = (int) Math.round((10 + d.y) * 6000);

        minX = (minX == -1) ? magnifiedX : Math.min(minX, magnifiedX);
        minY = (minY == -1) ? magnifiedY : Math.min(minY, magnifiedY);

        xys.add(new Point2D.Double(magnifiedX, magnifiedY));
    }

    return xys;
}

...

通过使用生成的 XY 坐标,地图看起来是倒置的,这是因为我相信 Graphics2D 的 0,0 从左上角开始。所以,我需要通过从图像高度中减去该值来反转 Y,如下所示:-

...

Polygon polygon = new Polygon();

for (Point2D.Double point : xys) {
    int adjustedX = (int) (IMAGE_PADDING + (point.getX() - minX));

    // need to invert the Y since 0,0 starts at top left
    int adjustedY = (int) (IMAGE_HEIGHT - IMAGE_PADDING - (point.getY() - minY));

    polygon.addPoint(adjustedX, adjustedY);
}

...

这是生成的地图:-

这十分完美!

更新 01-25-2013

以下是根据宽度和高度(以像素为单位)创建图像映射的代码。在本例中,我不依赖 Java Map Project Library,而是提取相关公式并将其嵌入到我的代码中。与上面依赖任意缩放值的代码示例(上面的示例使用 6000)相比,这使您可以更好地控制地图生成。

public class MapService {
    // CHANGE THIS: the output path of the image to be created
    private static final String IMAGE_FILE_PATH = "/some/user/path/map.png";

    // CHANGE THIS: image width in pixel
    private static final int IMAGE_WIDTH_IN_PX = 300;

    // CHANGE THIS: image height in pixel
    private static final int IMAGE_HEIGHT_IN_PX = 500;

    // CHANGE THIS: minimum padding in pixel
    private static final int MINIMUM_IMAGE_PADDING_IN_PX = 50;

    // formula for quarter PI
    private final static double QUARTERPI = Math.PI / 4.0;

    // some service that provides the county boundaries data in longitude and latitude
    private CountyService countyService;

    public void run() throws Exception {
        // configuring the buffered image and graphics to draw the map
        BufferedImage bufferedImage = new BufferedImage(IMAGE_WIDTH_IN_PX,
                                                        IMAGE_HEIGHT_IN_PX,
                                                        BufferedImage.TYPE_INT_RGB);

        Graphics2D g = bufferedImage.createGraphics();
        Map<RenderingHints.Key, Object> map = new HashMap<RenderingHints.Key, Object>();
        map.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
        map.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        map.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        RenderingHints renderHints = new RenderingHints(map);
        g.setRenderingHints(renderHints);

        // min and max coordinates, used in the computation below
        Point2D.Double minXY = new Point2D.Double(-1, -1);
        Point2D.Double maxXY = new Point2D.Double(-1, -1);

        // a list of counties where each county contains a list of coordinates that form the county boundary
        Collection<Collection<Point2D.Double>> countyBoundaries = new ArrayList<Collection<Point2D.Double>>();

        // for every county, convert the longitude/latitude to X/Y using Mercator projection formula
        for (County county : countyService.getAllCounties()) {
            Collection<Point2D.Double> lonLat = new ArrayList<Point2D.Double>();

            for (CountyBoundary countyBoundary : county.getCountyBoundaries()) {
                // convert to radian
                double longitude = countyBoundary.getLongitude() * Math.PI / 180;
                double latitude = countyBoundary.getLatitude() * Math.PI / 180;

                Point2D.Double xy = new Point2D.Double();
                xy.x = longitude;
                xy.y = Math.log(Math.tan(QUARTERPI + 0.5 * latitude));

                // The reason we need to determine the min X and Y values is because in order to draw the map,
                // we need to offset the position so that there will be no negative X and Y values
                minXY.x = (minXY.x == -1) ? xy.x : Math.min(minXY.x, xy.x);
                minXY.y = (minXY.y == -1) ? xy.y : Math.min(minXY.y, xy.y);

                lonLat.add(xy);
            }

            countyBoundaries.add(lonLat);
        }

        // readjust coordinate to ensure there are no negative values
        for (Collection<Point2D.Double> points : countyBoundaries) {
            for (Point2D.Double point : points) {
                point.x = point.x - minXY.x;
                point.y = point.y - minXY.y;

                // now, we need to keep track the max X and Y values
                maxXY.x = (maxXY.x == -1) ? point.x : Math.max(maxXY.x, point.x);
                maxXY.y = (maxXY.y == -1) ? point.y : Math.max(maxXY.y, point.y);
            }
        }

        int paddingBothSides = MINIMUM_IMAGE_PADDING_IN_PX * 2;

        // the actual drawing space for the map on the image
        int mapWidth = IMAGE_WIDTH_IN_PX - paddingBothSides;
        int mapHeight = IMAGE_HEIGHT_IN_PX - paddingBothSides;

        // determine the width and height ratio because we need to magnify the map to fit into the given image dimension
        double mapWidthRatio = mapWidth / maxXY.x;
        double mapHeightRatio = mapHeight / maxXY.y;

        // using different ratios for width and height will cause the map to be stretched. So, we have to determine
        // the global ratio that will perfectly fit into the given image dimension
        double globalRatio = Math.min(mapWidthRatio, mapHeightRatio);

        // now we need to readjust the padding to ensure the map is always drawn on the center of the given image dimension
        double heightPadding = (IMAGE_HEIGHT_IN_PX - (globalRatio * maxXY.y)) / 2;
        double widthPadding = (IMAGE_WIDTH_IN_PX - (globalRatio * maxXY.x)) / 2;

        // for each country, draw the boundary using polygon
        for (Collection<Point2D.Double> points : countyBoundaries) {
            Polygon polygon = new Polygon();

            for (Point2D.Double point : points) {
                int adjustedX = (int) (widthPadding + (point.getX() * globalRatio));

                // need to invert the Y since 0,0 starts at top left
                int adjustedY = (int) (IMAGE_HEIGHT_IN_PX - heightPadding - (point.getY() * globalRatio));

                polygon.addPoint(adjustedX, adjustedY);
            }

            g.drawPolygon(polygon);
        }

        // create the image file
        ImageIO.write(bufferedImage, "PNG", new File(IMAGE_FILE_PATH));
    }
}

结果:图像宽度 = 600 像素,图像高度 = 600 像素,图像填充 = 50 像素

结果:图像宽度 = 300 像素,图像高度 = 500 像素,图像填充 = 50 像素


绘制地图的一个大问题是地球的球形表面无法方便地转换为平面表示。有许多不同的预测试图解决这个问题。

Mercator http://en.wikipedia.org/wiki/Mercator_projection是最简单的之一:它假设等纬度的线是平行的水平线,而等经度的线是平行的垂直线。这对于纬度有效(无论你在哪里,1 度纬度约等于 111 公里),但对于经度无效(一定经度的表面距离与经度的余弦成正比)纬度).

然而,只要温度低于 45 度(明尼苏达州的大部分地区都是如此),墨卡托投影就可以很好地工作,并创建大多数人会从小学地图中识别的形式。这非常简单:只需将这些点视为绝对坐标,然后缩放到您在其中绘制它们的任何空间。无需触发。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将经度/纬度转换为 X/Y 坐标 的相关文章

  • AES 在 cryptojs 中加密并在 python Crypto.Cipher 中解密

    使用 js CryptoJS 加密并使用 python crypto Cipher 解密时出现问题 这是我在js中的实现 附加 iv 与加密消息并使用 base64 进行编码
  • 使用空的weak_ptr作为参数调用map::count安全吗?

    打电话安全吗map count http www cplusplus com reference map map count on an 未初始化因此为空weak ptr http en cppreference com w cpp mem
  • 使用 DataMapper 而不是 ActiveRecord [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 将同步 zip 操作转换为异步

    我们有一个现有的库 其中一些方法需要转换为异步方法 但是我不确定如何使用以下方法执行此操作 错误处理已被删除 该方法的目的是压缩文件并将其保存到磁盘 请注意 zip 类不公开任何异步方法 public static bool ZipAndS
  • Adobe Illustrator 中的折线简化如何工作?

    我正在开发一个记录笔划的应用程序 您可以使用定点设备来绘制笔划 在上图中 我绘制了一个笔划 其中包含 453 个数据点 我的目标是大幅减少数据点的数量 同时仍然保持原始笔画的形状 对于那些感兴趣的人 上图笔画的坐标可以作为GitHub 上的
  • 扩展Android应用程序类

    当我正在寻找从远程设备获取错误报告的解决方案时 就像 iOS 中的试飞应用程序一样 我发现了acra适用于 Android 设备here http code google com p acra wiki BasicSetup 在基本设置中
  • Turbolinks 访问的页面中缺少 hubspot 聊天界面,但可用于全页面刷新

    我想将 hubspot 聊天界面集成到我的 Rails 4 Turbolinks 应用程序中 我已将 Google 跟踪代码管理器配置为在每个页面加载事件中显示支持聊天界面 该界面工作正常 GTM 标签 自定义 html PROBLEM 当
  • 如何从 python 中的字符串中删除 ANSI 转义序列

    这是包含我的字符串的片段 ls r n x1b 00m x1b 01 31mexamplefile zip x1b 00m r n x1b 01 31m 该字符串是从我执行的 SSH 命令返回的 我无法使用当前状态下的字符串 因为它包含 A
  • NHibernate:无状态会话错误消息无法获取代理

    我正在使用 nHibernate 无状态会话来获取对象 更新一个属性并将对象保存回数据库 我不断收到错误消息 无状态会话无法获取代理 我在其他地方有类似的代码 所以我不明白为什么这不起作用 有谁知道问题可能是什么 我正在尝试更新Screen
  • IIS 中的 WIX 和证书

    我正在尝试设置我的安装 以便使用 WIX 配置我的站点及其证书 我可以在 IIS 中查看证书并有权访问 cer 文件 这就是我对证书的了解 所以请简化任何答案 即我不知道我的 BinaryKey 是什么 该证书已安装在计算机上 理想情况下
  • 如何从我的 appDelegate 访问我的 viewController? iOS系统

    我有一个在 xCode 中创建为 基于视图的应用程序 的 iOS 应用程序 我只有一个 viewController 但它会自动显示 而且我没有看到任何将它与我的 appDelegate 关联的代码 我需要将数据从 appDelegate
  • .gitignore:如何忽略嵌套目录?

    我有以下目录结构 test a test b c test a b Ouput test c d e Output test f Output 我想忽略 test 下的所有 Output 目录 我试过test Output 但没有成功 我究
  • 如何从Python枚举类中获取所有值?

    我正在使用 Enum4 库创建一个枚举类 如下所示 class Color Enum RED 1 BLUE 2 我要打印 1 2 作为某处的列表 我怎样才能实现这个目标 您可以执行以下操作 e value for e in Color
  • 如何使用 Microsoft Graph API 更新 MailboxSettings

    我想从不同的日历更新邮箱设置 如何构建可以通过 Microsoft Graph 更新 MailboxSetting 的请求 这是我的代码示例 但有例外 代码示例 User obj GraphServiceClient Users roomC
  • AngularJS 中的全局模拟对象用于 jasmine/karma 测试

    我有一个正在模拟进行单元测试的对象 基本上在我的测试文件中 我将其模拟如下 var mockObject mockMethod1 function return true mockMethod2 function return true b
  • 如何在 Firefox 插件上使用 jQuery 1.5.2+?

    首先 我创建了一个接收参数并返回 jQuery 的函数 例如 function getjQuery window jquery code window return window jQuery 但后来我收到了一封评论电子邮件 他们告诉我必须
  • 在reactjs中停止超时?

    有没有办法可以杀死 摆脱 reactjs 中的超时 setTimeout function do something bind this 3000 通过某种点击或操作 我希望能够完全停止并结束超时 有没有办法做到这一点 谢谢 假设这种情况发
  • 使用 python/scipy 进行 voronoi 和 lloyd 松弛

    如何使用 Qhull 确定哪些 voronoi 单元 按索引 是 正确的 由 现有顶点 组成 我正在尝试使用 LLoyds 算法和 scipy spatial Voronoi 它是 Qhull 的包装器 生成的输入来执行约束松弛 就代码而言
  • 如何使用javascript取消设置变量? [复制]

    这个问题在这里已经有答案了 这是我到目前为止所尝试的 var nxt I am next window onscroll function var scr this pageYOffset if scr gt 400 console log
  • 应用服务器如何注入私有字段?

    我看到这个问题 注入私有 包或公共字段或提供 setter https stackoverflow com questions 2021716 inject into private package or public field or p

随机推荐

  • flot.js - 位置垂直刻度,但被切断并居中

    我使用 flot js 绘制 x 轴上带有时间戳的图表 由于我在这些图表上会有很多刻度 所以我垂直旋转它们 这样它们就不会重叠 这工作正常 但标签集中在刻度上 并且没有提供足够的空间 因此它们被切断 我没有使用ticrotor插件滴答声 h
  • UDP/TCP 打洞 vs UPnP vs STUN vs?

    我尝试制作一个 P2P 程序 需要帮助来穿越客户端的 NAT 我在 stackoverflow 上读过很多问题 但我从来不知道通过 NAT 的所有方法的缺点和优点是什么 有多少路由器支持哪些方法 大公司常用哪些方法 BitTorrent T
  • OSError:输入/输出错误 - Google Colab

    Using h5py File path r 或 喀拉斯 model load weights path on h5文件产生以下错误 我已经在 Colab 上训练模型几个月了 从来没有遇到过这个问题 从云端硬盘下载后 相同的文件在我的计算机
  • 使用 graphql 公开动态模式

    我的应用程序动态处理模式 用户可以上传新域或更改现有域的定义 例如 我发布的产品具有如下用户模式 user fn ln age Later user can change this definition to include new pro
  • 在 C++ 中修改后修复文件权限?

    我将数据保存在程序的可执行文件中 我将其复制到临时文件中 覆盖从 a 开始的部分 神奇的字符串 并将其重命名为原来的 我知道这是一个坏主意 但我这样做只是为了实验 到目前为止 一切正常 除了每次替换文件时我必须重新启用 允许作为可执行文件运
  • 远程检查交换凭据并检查登录的用户

    我曾尝试过这一点 但没有取得多大成功 基本上我需要使用 EWS 远程登录 Exchange 问题是我不知道用户是否已正常登录 或者凭据是否错误 因为我没有得到任何回报 如果我提供了错误的凭据 软件就会继续运行 我是否遗漏了一些东西 我已经检
  • 无法导入模块

    首先 这很可能不是路径问题 我在 eclipse 中有一个 pydev 项目 这是目录结构 Genetic Framework Genetic Framework Genetic init py GA py crossover py fit
  • 如何测量 x86 纳秒以下的运行时间?

    我搜索并使用了许多方法来测量经过的时间 为此目的有很多问题 例如 this https stackoverflow com questions 6749621 how to create a high resolution timer in
  • 访问函数内的函数(嵌套函数?)[重复]

    这个问题在这里已经有答案了 这里是Python菜鸟 如何获取 fib 函数中的 内部 函数 from time import sleep class Fibonacci object def init self a b limit 50 s
  • 这个Timer会从内存中释放吗?

    考虑 C 中的这对函数 void func1 DispatcherTimer tmr new DispatcherTimer tmr Interval TimeSpan FromSeconds 5 tmr Tick func2 tmr St
  • C# 是单调度语言还是多调度语言?

    我试图准确理解什么是单次调度和多次调度 我刚刚读过这个 http en wikipedia org wiki Multiple dispatch http en wikipedia org wiki Multiple dispatch 从这
  • 使用实体框架作为 ORM 的 winform 应用程序的 MVC 或 MVP 架构

    我要开发一个相当规模的winform项目 我打算使用实体框架作为 ORM 工具 现在我正在寻找一种架构 MVC MVP MVVM 等 来实现所有这些 首先 Windows 窗体的 n 层架构的选择很少 而且我得到的大多数都是在 EF 进入市
  • ActionScript:一个 .as 文件中有多个公共函数?

    当我一直在使用 AS 时 我开发了一系列实用函数 例如 cat utils curried as package utils public function curried f Function boundArgs Function fun
  • conhost.exe 似乎泄漏内存

    我有一个在 IIS 中运行的 NET Framework ASP NET 应用程序 该应用程序启动了一个长期存在的子流程 但在其他方面并不引人注目 只有一个端点有效地将请求代理到子流程 当系统处理请求时 计算机上 conhost exe 的
  • 在 SQLite 语句中使用 NSString/参数 iOS

    我的代码如下 我的价值观 emailVaue passwordValue and nameValue取自UITextFields在我的应用程序中 我的印象是 将这些值传递到我的 SQLite 代码中的参数中将允许我在这些值中包含特殊字符 例
  • 结合Google Maps Geocoder和Leaflet地图接收错误:无效的LatLng对象

    我正在使用 Google 地图地理编码器来获取地址的纬度和经度 然后 我获取该地址并使用 Leaflet 并将地图平移到纬度 经度坐标 但是 我收到 Firebug 的错误消息Error Invalid LatLng object 33 8
  • 无法加载驱动程序:com.microsoft.sqlserver.jdbc.SQLServerDriver weblogic 10g

    我正在尝试创建从 weblogic 10 3 到 sqlserverexpress 2008 r2 的数据源 但是当我测试连接时 出现以下消息 无法加载驱动程序 com microsoft sqlserver jdbc SQLServerD
  • 如何通过API“input type='file'”标签更改本地文件的视频源...没有Jquery或外部库

    我正在尝试通过 API input type file 标签使用本地文件更改 HTML5 视频源 此 HTML 脚本旨在仅在本地运行 播放我的高清视频 但我无法获取 输入 标签来选择和播放我的高清视频文件 jsfiddle 示例 https
  • 为什么 SQL Server 中的 CONVERT string to VARBINARY 只转换第一个字符?

    我使用 NLog 登录我的应用程序 作为其中的一部分 我们记录客户编号 C 中的字符串 和数据库中的 varbinary 32 我针对此特定参数使用以下 SQL 代码 SQL 语句的其余部分工作正常 CONVERT varbinary 32
  • 将经度/纬度转换为 X/Y 坐标

    我使用 Google Maps API 创建了一张地图 突出显示了明尼苏达州的所有县 基本上 我使用一组经度 纬度坐标创建了县多边形 这是生成的地图的屏幕截图 用户要求之一是能够拥有与图像类似的地图 以便他们可以将其嵌入到 PowerPoi