在 SVG 中绘制经纬度坐标
Plotting a Latitude and Longitude Coordinate in SVG
总结
我正在尝试读取 .SCT
文件,该文件是由名为 VRC 的程序创建的自定义文件类型。我使用此文件在我的源区域内绘制经纬度坐标。我遇到的问题是大多数经纬度坐标没有正确映射。似乎大多数坐标都映射到某个任意点。
背景
这是我目前用于将它们转换并绘制到 SVG.js canvas.
中的代码示例
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
引用的 Whosebug 问题: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
这实际上是 SVG.js 库的错误文档的问题。如果您将转换定义为
element.transform({ scale: 30000 })
结果不是具有值 scale(30000)
的 transform
属性,这意味着在点 (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});
如果您想获得定义大小的结果地图,上述解决方案很好。如果你想找到一个实际让内容从一边到另一边填满你的 canvas 的比例值,这很简单:你可以获取组的边界框,并将它们设置为视图框<svg>
元素。然后浏览器会注意缩放该框以适合 canvas.
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);
总结
我正在尝试读取 .SCT
文件,该文件是由名为 VRC 的程序创建的自定义文件类型。我使用此文件在我的源区域内绘制经纬度坐标。我遇到的问题是大多数经纬度坐标没有正确映射。似乎大多数坐标都映射到某个任意点。
背景
这是我目前用于将它们转换并绘制到 SVG.js canvas.
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
引用的 Whosebug 问题: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
这实际上是 SVG.js 库的错误文档的问题。如果您将转换定义为
element.transform({ scale: 30000 })
结果不是具有值 scale(30000)
的 transform
属性,这意味着在点 (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});
如果您想获得定义大小的结果地图,上述解决方案很好。如果你想找到一个实际让内容从一边到另一边填满你的 canvas 的比例值,这很简单:你可以获取组的边界框,并将它们设置为视图框<svg>
元素。然后浏览器会注意缩放该框以适合 canvas.
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);