Построение координат широты и долготы в SVG - PullRequest
0 голосов
/ 05 января 2019

Резюме
Я пытаюсь прочитать файл .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, поэтому я не смог создать тестовый сценарий. Я приложил все необходимые файлы, чтобы вы могли работать локально.

Моя главная проблема заключается в том, что все координаты отображаются в какую-то произвольную точку.

Источники
Вот как должно выглядеть изображение enter image description here

Как это выглядит в данный момент: enter image description here

Документация файла сектора VRC: http://www1.metacraft.com/VRC/docs/doc.php?page=appendix_g

StackOverflow Ссылка на вопрос: Преобразование точки широты / долготы в пиксели (x, y) на проекции меркатора

Используемая библиотека
svg.js: https://svgjs.com/
svg.panzoom.js: https://github.com/svgdotjs/svg.panzoom.js

1 Ответ

0 голосов
/ 05 января 2019

Это на самом деле проблема с плохой документацией для библиотеки SVG.js. Если вы определяете преобразование как

element.transform({ scale: 30000 })

результатом является не атрибут transform со значением scale(30000), который будет означать начало координат для масштабирования в точке (0, 0), а матрица преобразования, которая эквивалентна масштабированию вокруг центр ограничивающей рамки элемента .

В вашем коде каждая частичная фигура рисуется в виде отдельной ломаной линии и отдельно масштабируется вокруг ее отдельного центра . Элемент, до масштабирования, чрезвычайно мал, и все элементы настолько сгруппированы, что фактически находятся в одной точке. Если они масштабируются, результат выглядит так, как будто все элементы имеют эту общую точку в своем новом размере.

Наиболее очевидным решением является масштабирование элементов не вокруг их отдельного центра, а вокруг одного постоянного значения:

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

Что это за значение, не сразу понятно. Это будет точка, которая находится в центре общей ограничительной рамки всех полилиний. Как ты к этому относишься? Пусть библиотека сделает всю работу за вас.

Если вы добавите все полилинии как дочерние элементы элемента <g>, вы можете масштабировать эту группу, и если вы пропустите значения для центра, они будут вычислены для вас:

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});

Приведенное выше решение хорошо, если вы хотите получить результирующую карту определенного размера. Если вы хотите найти значение масштаба, которое фактически позволяет содержимому заполнять ваш холст из стороны в сторону, это так же просто: вы можете получить ограничивающий прямоугольник группы и установить их в качестве окна просмотра для элемента <svg> , После этого браузер позаботится о том, чтобы масштабировать это поле по размеру холста.

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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...