【问题标题】:Plotting a Latitude and Longitude Coordinate in SVG在 SVG 中绘制经纬度坐标
【发布时间】:2019-05-31 13:31:28
【问题描述】:

总结
我正在尝试读取.SCT 文件,该文件是由名为 VRC 的程序创建的自定义文件类型。我使用这个文件在我的源区域内绘制经纬度坐标。我遇到的问题是大多数经纬度坐标都没有正确映射。似乎大多数坐标都映射到某个任意点。

背景
这是我目前用来将它们转换并绘制到 SVG.js 画布中的代码示例。

CODE [index.js(至少是活动部分)]

var coor = [];
let fixed = [];

var dms2dd = function(object) {
  var deg = parseFloat(object.degrees),
      min = parseFloat(object.minutes),
      sec = parseFloat(object.seconds),
      dir = object.dir == "N" || object.dir == "E" ? 1 : -1;

  return dir*(deg+(min/60.0)+(sec/3600.0));
};

function llToXY(arr) {
    mapWidth    = 1000;
    mapHeight   = 1000;

    // get x value
    x = (arr[1]+180)*(mapWidth/360)

    // convert from degrees to radians
    latRad = arr[0]*Math.PI/180;

    // get y value
    mercN = Math.log(Math.tan((Math.PI/4)+(latRad/2)));
    y     = (mapHeight/2)-(mapWidth*mercN/(2*Math.PI));

    return [x, y];
}

lineReader.eachLine('test.txt', function(line, last) {
    let data = line.split(" ");
    let coor_length = coor.length;

    if (line[0] != " ") {
        coor.push({
            type: data[0],
            coordinates: []
        });

        // Convert to DD
        /*let direction = data[1].substr(0, 1);
        let dms = data[1].split(".")
        dms2dd({

        })*/


        data.splice(0, 1);

        coor[coor.length - 1]["coordinates"].push(data.join(" "));
    } else {
        coor[coor_length - 1]["coordinates"].push(line.trim())
    }

    if (last) {
        coor.forEach((data, index) => {
            for (coordinate_pair in data["coordinates"]) {
                let pair = data["coordinates"][coordinate_pair];

                pair = pair.split(" ");

                let x_data = pair[0].split("."),
                    y_data = pair[1].split(".");

                let x = dms2dd({
                    degrees: x_data[0].substring(1),
                    minutes: parseFloat(x_data[1]),
                    seconds: parseFloat(`${x_data[2]}.${x_data[3]}`),
                    dir: x_data[0].substr(0,1)
                });

                let y = dms2dd({
                    degrees: y_data[0].substring(1),
                    minutes: parseFloat(y_data[1]),
                    seconds: parseFloat(`${y_data[2]}.${y_data[3]}`),
                    dir: y_data[0].substr(0,1)
                });

                console.log([x, y]);
                coor[index]["coordinates"][coordinate_pair] = llToXY([x, y]);
            }
        })

        return false;
    }
});

绘图代码

let draw = SVG("drawing").size(1000, 1000).panZoom();
            let cp = <%- JSON.stringify(cp) %>;
            //var line = draw.plot([32.737396,117.204284], [32.736862,117.204468], [32.737396,117.204284], [32.736862,117.204468]).stroke({ width: 1 })
            // var line = draw.polyline().fill("none").stroke({width: 0.00005});
            // line.transform({
            //     scale: 50000
            // }).transform({rotation: 104.5});

            cp.forEach((data)=> {
                //draw.polyline(data.coordinates.join(" "))
                //llToXY(data.coordinates);
                draw.polyline(data.coordinates.join(" ")).fill("none").stroke({width: 0.00005}).transform({scale: 50000}).transform({rotation: -15.80})
            });

此代码基本上是逐行读取文本文件并将数据插入到名为coor 的变量中。一旦代码到达最后一行,它会将所有坐标(即coor)值转换为十进制度。

不幸的是,该库与 JSFiddle 不兼容,因此我无法制作测试场景。我已经附上了所有必要的文件,所以你可以在本地运行。

我主要担心的是所有坐标都映射到某个任意点。

来源
这就是图像应该看起来的样子

目前的样子:

VRC 扇区文件文档:http://www1.metacraft.com/VRC/docs/doc.php?page=appendix_g

引用的 StackOverflow 问题:Convert latitude/longitude point to a pixels (x,y) on mercator projection

使用的库
svg.js:https://svgjs.dev/
svg.panzoom.js: https://github.com/svgdotjs/svg.panzoom.js

【问题讨论】:

    标签: javascript svg latitude-longitude


    【解决方案1】:

    这实际上是 SVG.js 库的错误文档的问题。如果您将转换定义为

    element.transform({ scale: 30000 })
    

    结果不是具有值scale(30000)transform 属性,这意味着在点 (0, 0) 处缩放的原点,而是等效于围绕元素边界框的中心。

    在您的代码中,每个部分形状都被绘制为单独的折线,并分别围绕其各自的中心进行缩放。缩放之前的元素非常小,所有元素都紧密地组合在一起,几乎在一个点上。如果它们被缩放,结果看起来就像所有元素在新尺寸下都将该点作为一个公共中心。

    最明显的解决方案是缩放元素,而不是围绕它们各自的中心,而是围绕一个常数值:

    const cx = ..., cy = ...
    element.transform({ scale: 30000, cx, cy })
    

    该值是什么尚不清楚。这将是所有折线的公共边界框中心的一个点。你是怎么做到的?让图书馆为您完成工作。

    如果您将所有折线添加为 &lt;g&gt; 元素的子元素,您可以缩放该组,如果您忽略中心的值,则会为您计算它们:

    let draw = SVG("drawing").size(1000, 1000).panZoom();
    let g = draw.group();
    
    let cp = <%- JSON.stringify(cp) %>;
    cp.forEach((data) => {
        group.polyline(data.coordinates.join(" "))
           .fill("none")
           .stroke({width: 0.00005});
    });
    
    group.transform({scale: 50000}).transform({rotation: -15.80});
    

    如果您想以定义的大小获取结果地图,上述解决方案非常有用。如果你想找到一个真正让内容从一边到另一边填充画布的比例值,它同样简单:你可以获取组的边界框,并将它们设置为 &lt;svg&gt; 元素上的视图框.然后浏览器会注意缩放该框以适合画布。

    let draw = SVG("drawing").size(1000, 1000).panZoom();
    let g = draw.group();
    
    let cp = <%- JSON.stringify(cp) %>;
    cp.forEach((data) => {
        group.polyline(data.coordinates.join(" "))
           .fill("none")
           .stroke({width: 0.00005});
    });
    
    const { x, y, w, h } = group.bbox();
    draw.viewbox(x, y w, h);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-15
      • 2021-04-09
      • 2014-02-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多